1 /*
2  *  cHardwareCPU.cc
3  *  Avida
4  *
5  *  Called "hardware_cpu.cc" prior to 11/17/05.
6  *  Copyright 1999-2011 Michigan State University. All rights reserved.
7  *  Copyright 1999-2003 California Institute of Technology.
8  *
9  *
10  *  This file is part of Avida.
11  *
12  *  Avida is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License
13  *  as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
14  *
15  *  Avida is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
17  *
18  *  You should have received a copy of the GNU Lesser General Public License along with Avida.
19  *  If not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22 
23 
24 #include "cHardwareCPU.h"
25 
26 #include "avida/core/WorldDriver.h"
27 
28 #include "cAvidaContext.h"
29 #include "cBioGroup.h"
30 #include "cCPUTestInfo.h"
31 #include "cEnvironment.h"
32 #include "cHardwareManager.h"
33 #include "cHardwareTracer.h"
34 #include "cInstSet.h"
35 #include "cOrganism.h"
36 #include "cOrgMessage.h"
37 #include "cPhenotype.h"
38 #include "cPopulation.h"
39 #include "cPopulationCell.h"
40 #include "cReaction.h"
41 #include "cReactionLib.h"
42 #include "cReactionProcess.h"
43 #include "cResource.h"
44 #include "cSexualAncestry.h"
45 #include "cStateGrid.h"
46 #include "cStringUtil.h"
47 #include "cTestCPU.h"
48 #include "cWorld.h"
49 #include "tInstLibEntry.h"
50 
51 #include "AvidaTools.h"
52 
53 #include <climits>
54 #include <fstream>
55 #include <cmath>
56 
57 using namespace std;
58 using namespace Avida;
59 using namespace AvidaTools;
60 
61 
62 tInstLib<cHardwareCPU::tMethod>* cHardwareCPU::s_inst_slib = cHardwareCPU::initInstLib();
63 
initInstLib(void)64 tInstLib<cHardwareCPU::tMethod>* cHardwareCPU::initInstLib(void)
65 {
66   struct cNOPEntryCPU {
67     cString name;
68     int nop_mod;
69     cNOPEntryCPU(const cString &name, int nop_mod)
70     : name(name), nop_mod(nop_mod) {}
71   };
72   static const cNOPEntryCPU s_n_array[] = {
73     cNOPEntryCPU("nop-A", REG_AX),
74     cNOPEntryCPU("nop-B", REG_BX),
75     cNOPEntryCPU("nop-C", REG_CX)
76   };
77 
78   static const tInstLibEntry<tMethod> s_f_array[] = {
79     /*
80      Note: all entries of cNOPEntryCPU s_n_array must have corresponding
81      in the same order in tInstLibEntry<tMethod> s_f_array, and these entries must
82      be the first elements of s_f_array.
83      */
84     tInstLibEntry<tMethod>("nop-A", &cHardwareCPU::Inst_Nop, (nInstFlag::DEFAULT | nInstFlag::NOP), "No-operation instruction; modifies other instructions"),
85     tInstLibEntry<tMethod>("nop-B", &cHardwareCPU::Inst_Nop, (nInstFlag::DEFAULT | nInstFlag::NOP), "No-operation instruction; modifies other instructions"),
86     tInstLibEntry<tMethod>("nop-C", &cHardwareCPU::Inst_Nop, (nInstFlag::DEFAULT | nInstFlag::NOP), "No-operation instruction; modifies other instructions"),
87 
88     tInstLibEntry<tMethod>("nop-X", &cHardwareCPU::Inst_Nop, 0, "True no-operation instruction: does nothing"),
89     tInstLibEntry<tMethod>("if-equ-0", &cHardwareCPU::Inst_If0, 0, "Execute next instruction if ?BX?==0, else skip it"),
90     tInstLibEntry<tMethod>("if-not-0", &cHardwareCPU::Inst_IfNot0, 0, "Execute next instruction if ?BX?!=0, else skip it"),
91     tInstLibEntry<tMethod>("if-equ-0-defaultAX", &cHardwareCPU::Inst_If0_defaultAX, 0, "Execute next instruction if ?AX?==0, else skip it"),
92     tInstLibEntry<tMethod>("if-not-0-defaultAX", &cHardwareCPU::Inst_IfNot0_defaultAX, 0, "Execute next instruction if ?AX?!=0, else skip it"),
93     tInstLibEntry<tMethod>("if-n-equ", &cHardwareCPU::Inst_IfNEqu, nInstFlag::DEFAULT, "Execute next instruction if ?BX?!=?CX?, else skip it"),
94     tInstLibEntry<tMethod>("if-equ", &cHardwareCPU::Inst_IfEqu, 0, "Execute next instruction if ?BX?==?CX?, else skip it"),
95     tInstLibEntry<tMethod>("if-grt-0", &cHardwareCPU::Inst_IfGr0),
96     tInstLibEntry<tMethod>("if-grt", &cHardwareCPU::Inst_IfGr),
97     tInstLibEntry<tMethod>("if->=-0", &cHardwareCPU::Inst_IfGrEqu0),
98     tInstLibEntry<tMethod>("if->=", &cHardwareCPU::Inst_IfGrEqu),
99     tInstLibEntry<tMethod>("if-les-0", &cHardwareCPU::Inst_IfLess0),
100     tInstLibEntry<tMethod>("if-less", &cHardwareCPU::Inst_IfLess, nInstFlag::DEFAULT, "Execute next instruction if ?BX? < ?CX?, else skip it"),
101     tInstLibEntry<tMethod>("if-<=-0", &cHardwareCPU::Inst_IfLsEqu0),
102     tInstLibEntry<tMethod>("if-<=", &cHardwareCPU::Inst_IfLsEqu),
103     tInstLibEntry<tMethod>("if-A!=B", &cHardwareCPU::Inst_IfANotEqB),
104     tInstLibEntry<tMethod>("if-B!=C", &cHardwareCPU::Inst_IfBNotEqC),
105     tInstLibEntry<tMethod>("if-A!=C", &cHardwareCPU::Inst_IfANotEqC),
106     tInstLibEntry<tMethod>("if-bit-1", &cHardwareCPU::Inst_IfBit1),
107     tInstLibEntry<tMethod>("if-grt-X", &cHardwareCPU::Inst_IfGrX),
108     tInstLibEntry<tMethod>("if-equ-X", &cHardwareCPU::Inst_IfEquX),
109 
110     tInstLibEntry<tMethod>("if-aboveResLevel", &cHardwareCPU::Inst_IfAboveResLevel),
111     tInstLibEntry<tMethod>("if-aboveResLevel.end", &cHardwareCPU::Inst_IfAboveResLevelEnd),
112     tInstLibEntry<tMethod>("if-notAboveResLevel", &cHardwareCPU::Inst_IfNotAboveResLevel),
113     tInstLibEntry<tMethod>("if-notAboveResLevel.end", &cHardwareCPU::Inst_IfNotAboveResLevelEnd),
114 
115     tInstLibEntry<tMethod>("if-germ", &cHardwareCPU::Inst_IfGerm),
116     tInstLibEntry<tMethod>("if-soma", &cHardwareCPU::Inst_IfSoma),
117 
118     // Probabilistic ifs.
119     tInstLibEntry<tMethod>("if-p-0.125", &cHardwareCPU::Inst_IfP0p125, nInstFlag::STALL),
120     tInstLibEntry<tMethod>("if-p-0.25", &cHardwareCPU::Inst_IfP0p25, nInstFlag::STALL),
121     tInstLibEntry<tMethod>("if-p-0.50", &cHardwareCPU::Inst_IfP0p50, nInstFlag::STALL),
122     tInstLibEntry<tMethod>("if-p-0.75", &cHardwareCPU::Inst_IfP0p75, nInstFlag::STALL),
123 
124     // The below series of conditionals extend the traditional Avida single-instruction-skip
125     // to a block, or series of instructions.
126     tInstLibEntry<tMethod>("if-less.end", &cHardwareCPU::Inst_IfLessEnd, nInstFlag::STALL),
127     tInstLibEntry<tMethod>("if-n-equ.end", &cHardwareCPU::Inst_IfNotEqualEnd, nInstFlag::STALL),
128     tInstLibEntry<tMethod>("if->=.end", &cHardwareCPU::Inst_IfGrtEquEnd, nInstFlag::STALL),
129     tInstLibEntry<tMethod>("else", &cHardwareCPU::Inst_Else, nInstFlag::STALL),
130     tInstLibEntry<tMethod>("end-if", &cHardwareCPU::Inst_EndIf, nInstFlag::STALL),
131 
132     tInstLibEntry<tMethod>("jump-f", &cHardwareCPU::Inst_JumpF),
133     tInstLibEntry<tMethod>("jump-b", &cHardwareCPU::Inst_JumpB),
134     tInstLibEntry<tMethod>("call", &cHardwareCPU::Inst_Call),
135     tInstLibEntry<tMethod>("return", &cHardwareCPU::Inst_Return),
136 
137     tInstLibEntry<tMethod>("throw", &cHardwareCPU::Inst_Throw),
138     tInstLibEntry<tMethod>("throwif=0", &cHardwareCPU::Inst_ThrowIf0),
139     tInstLibEntry<tMethod>("throwif!=0", &cHardwareCPU::Inst_ThrowIfNot0),
140     tInstLibEntry<tMethod>("catch", &cHardwareCPU::Inst_Catch),
141 
142     tInstLibEntry<tMethod>("goto", &cHardwareCPU::Inst_Goto),
143     tInstLibEntry<tMethod>("goto-if=0", &cHardwareCPU::Inst_GotoIf0),
144     tInstLibEntry<tMethod>("goto-if!=0", &cHardwareCPU::Inst_GotoIfNot0),
145     tInstLibEntry<tMethod>("label", &cHardwareCPU::Inst_Label),
146 
147     tInstLibEntry<tMethod>("pop", &cHardwareCPU::Inst_Pop, nInstFlag::DEFAULT, "Remove top number from stack and place into ?BX?"),
148     tInstLibEntry<tMethod>("push", &cHardwareCPU::Inst_Push, nInstFlag::DEFAULT, "Copy number from ?BX? and place it into the stack"),
149     tInstLibEntry<tMethod>("swap-stk", &cHardwareCPU::Inst_SwitchStack, nInstFlag::DEFAULT, "Toggle which stack is currently being used"),
150     tInstLibEntry<tMethod>("flip-stk", &cHardwareCPU::Inst_FlipStack),
151     tInstLibEntry<tMethod>("swap", &cHardwareCPU::Inst_Swap, nInstFlag::DEFAULT, "Swap the contents of ?BX? with ?CX?"),
152     tInstLibEntry<tMethod>("swap-AB", &cHardwareCPU::Inst_SwapAB),
153     tInstLibEntry<tMethod>("swap-BC", &cHardwareCPU::Inst_SwapBC),
154     tInstLibEntry<tMethod>("swap-AC", &cHardwareCPU::Inst_SwapAC),
155     tInstLibEntry<tMethod>("copy-reg", &cHardwareCPU::Inst_CopyReg),
156     tInstLibEntry<tMethod>("set_A=B", &cHardwareCPU::Inst_CopyRegAB),
157     tInstLibEntry<tMethod>("set_A=C", &cHardwareCPU::Inst_CopyRegAC),
158     tInstLibEntry<tMethod>("set_B=A", &cHardwareCPU::Inst_CopyRegBA),
159     tInstLibEntry<tMethod>("set_B=C", &cHardwareCPU::Inst_CopyRegBC),
160     tInstLibEntry<tMethod>("set_C=A", &cHardwareCPU::Inst_CopyRegCA),
161     tInstLibEntry<tMethod>("set_C=B", &cHardwareCPU::Inst_CopyRegCB),
162     tInstLibEntry<tMethod>("reset", &cHardwareCPU::Inst_Reset),
163 
164     tInstLibEntry<tMethod>("pop-A", &cHardwareCPU::Inst_PopA),
165     tInstLibEntry<tMethod>("pop-B", &cHardwareCPU::Inst_PopB),
166     tInstLibEntry<tMethod>("pop-C", &cHardwareCPU::Inst_PopC),
167     tInstLibEntry<tMethod>("push-A", &cHardwareCPU::Inst_PushA),
168     tInstLibEntry<tMethod>("push-B", &cHardwareCPU::Inst_PushB),
169     tInstLibEntry<tMethod>("push-C", &cHardwareCPU::Inst_PushC),
170 
171     tInstLibEntry<tMethod>("shift-r", &cHardwareCPU::Inst_ShiftR, nInstFlag::DEFAULT, "Shift bits in ?BX? right by one (divide by two)"),
172     tInstLibEntry<tMethod>("shift-l", &cHardwareCPU::Inst_ShiftL, nInstFlag::DEFAULT, "Shift bits in ?BX? left by one (multiply by two)"),
173     tInstLibEntry<tMethod>("bit-1", &cHardwareCPU::Inst_Bit1),
174     tInstLibEntry<tMethod>("set-num", &cHardwareCPU::Inst_SetNum),
175     tInstLibEntry<tMethod>("val-grey", &cHardwareCPU::Inst_ValGrey),
176     tInstLibEntry<tMethod>("val-dir", &cHardwareCPU::Inst_ValDir),
177     tInstLibEntry<tMethod>("val-add-p", &cHardwareCPU::Inst_ValAddP),
178     tInstLibEntry<tMethod>("val-fib", &cHardwareCPU::Inst_ValFib),
179     tInstLibEntry<tMethod>("val-poly-c", &cHardwareCPU::Inst_ValPolyC),
180     tInstLibEntry<tMethod>("inc", &cHardwareCPU::Inst_Inc, nInstFlag::DEFAULT, "Increment ?BX? by one"),
181     tInstLibEntry<tMethod>("dec", &cHardwareCPU::Inst_Dec, nInstFlag::DEFAULT, "Decrement ?BX? by one"),
182     tInstLibEntry<tMethod>("zero", &cHardwareCPU::Inst_Zero, 0, "Set ?BX? to zero"),
183     tInstLibEntry<tMethod>("all1s", &cHardwareCPU::Inst_All1s, 0, "Set ?BX? to all 1s in bitstring"),
184     tInstLibEntry<tMethod>("neg", &cHardwareCPU::Inst_Neg),
185     tInstLibEntry<tMethod>("square", &cHardwareCPU::Inst_Square),
186     tInstLibEntry<tMethod>("sqrt", &cHardwareCPU::Inst_Sqrt),
187     tInstLibEntry<tMethod>("not", &cHardwareCPU::Inst_Not),
188 
189     tInstLibEntry<tMethod>("add", &cHardwareCPU::Inst_Add, nInstFlag::DEFAULT, "Add BX to CX and place the result in ?BX?"),
190     tInstLibEntry<tMethod>("sub", &cHardwareCPU::Inst_Sub, nInstFlag::DEFAULT, "Subtract CX from BX and place the result in ?BX?"),
191     tInstLibEntry<tMethod>("mult", &cHardwareCPU::Inst_Mult, 0, "Multiple BX by CX and place the result in ?BX?"),
192     tInstLibEntry<tMethod>("div", &cHardwareCPU::Inst_Div, 0, "Divide BX by CX and place the result in ?BX?"),
193     tInstLibEntry<tMethod>("mod", &cHardwareCPU::Inst_Mod),
194     tInstLibEntry<tMethod>("nand", &cHardwareCPU::Inst_Nand, nInstFlag::DEFAULT, "Nand BX by CX and place the result in ?BX?"),
195     tInstLibEntry<tMethod>("or", &cHardwareCPU::Inst_Or),
196     tInstLibEntry<tMethod>("nor", &cHardwareCPU::Inst_Nor),
197     tInstLibEntry<tMethod>("and", &cHardwareCPU::Inst_And),
198     tInstLibEntry<tMethod>("order", &cHardwareCPU::Inst_Order),
199     tInstLibEntry<tMethod>("xor", &cHardwareCPU::Inst_Xor),
200 
201     // Instructions that modify specific bits in the register values
202     tInstLibEntry<tMethod>("setbit", &cHardwareCPU::Inst_Setbit, nInstFlag::DEFAULT, "Set the bit in ?BX? specified by ?BX?'s complement"),
203     tInstLibEntry<tMethod>("clearbit", &cHardwareCPU::Inst_Clearbit, nInstFlag::DEFAULT, "Clear the bit in ?BX? specified by ?BX?'s complement"),
204 
205     // treatable instructions
206     tInstLibEntry<tMethod>("nand-treatable", &cHardwareCPU::Inst_NandTreatable, nInstFlag::DEFAULT, "Nand BX by CX and place the result in ?BX?, fails if deme is treatable"),
207 
208     tInstLibEntry<tMethod>("copy", &cHardwareCPU::Inst_Copy),
209     tInstLibEntry<tMethod>("read", &cHardwareCPU::Inst_ReadInst),
210     tInstLibEntry<tMethod>("write", &cHardwareCPU::Inst_WriteInst),
211     tInstLibEntry<tMethod>("stk-read", &cHardwareCPU::Inst_StackReadInst),
212     tInstLibEntry<tMethod>("stk-writ", &cHardwareCPU::Inst_StackWriteInst),
213 
214     tInstLibEntry<tMethod>("compare", &cHardwareCPU::Inst_Compare),
215     tInstLibEntry<tMethod>("if-n-cpy", &cHardwareCPU::Inst_IfNCpy),
216     tInstLibEntry<tMethod>("allocate", &cHardwareCPU::Inst_Allocate),
217     tInstLibEntry<tMethod>("divide", &cHardwareCPU::Inst_Divide, nInstFlag::STALL),
218     tInstLibEntry<tMethod>("divideRS", &cHardwareCPU::Inst_DivideRS, nInstFlag::STALL),
219     tInstLibEntry<tMethod>("c-alloc", &cHardwareCPU::Inst_CAlloc),
220     tInstLibEntry<tMethod>("c-divide", &cHardwareCPU::Inst_CDivide, nInstFlag::STALL),
221     tInstLibEntry<tMethod>("transposon", &cHardwareCPU::Inst_Transposon),
222     tInstLibEntry<tMethod>("search-f", &cHardwareCPU::Inst_SearchF),
223     tInstLibEntry<tMethod>("search-b", &cHardwareCPU::Inst_SearchB),
224     tInstLibEntry<tMethod>("mem-size", &cHardwareCPU::Inst_MemSize),
225 
226     tInstLibEntry<tMethod>("get", &cHardwareCPU::Inst_TaskGet, nInstFlag::STALL),
227     tInstLibEntry<tMethod>("get-2", &cHardwareCPU::Inst_TaskGet2, nInstFlag::STALL),
228     tInstLibEntry<tMethod>("stk-get", &cHardwareCPU::Inst_TaskStackGet, nInstFlag::STALL),
229     tInstLibEntry<tMethod>("stk-load", &cHardwareCPU::Inst_TaskStackLoad, nInstFlag::STALL),
230     tInstLibEntry<tMethod>("put", &cHardwareCPU::Inst_TaskPut, nInstFlag::STALL),
231     tInstLibEntry<tMethod>("put-reset", &cHardwareCPU::Inst_TaskPutResetInputs, nInstFlag::STALL),
232     tInstLibEntry<tMethod>("IO", &cHardwareCPU::Inst_TaskIO, nInstFlag::DEFAULT | nInstFlag::STALL, "Output ?BX?, and input new number back into ?BX?"),
233     tInstLibEntry<tMethod>("IO-Feedback", &cHardwareCPU::Inst_TaskIO_Feedback, nInstFlag::STALL, "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"),
234     tInstLibEntry<tMethod>("IO-bc-0.001", &cHardwareCPU::Inst_TaskIO_BonusCost_0_001, nInstFlag::STALL),
235     tInstLibEntry<tMethod>("match-strings", &cHardwareCPU::Inst_MatchStrings, nInstFlag::STALL),
236     tInstLibEntry<tMethod>("sell", &cHardwareCPU::Inst_Sell, nInstFlag::STALL),
237     tInstLibEntry<tMethod>("buy", &cHardwareCPU::Inst_Buy, nInstFlag::STALL),
238     tInstLibEntry<tMethod>("send", &cHardwareCPU::Inst_Send, nInstFlag::STALL),
239     tInstLibEntry<tMethod>("receive", &cHardwareCPU::Inst_Receive, nInstFlag::STALL),
240     tInstLibEntry<tMethod>("sense", &cHardwareCPU::Inst_SenseLog2, nInstFlag::STALL),           // If you add more sense instructions
241     tInstLibEntry<tMethod>("sense-unit", &cHardwareCPU::Inst_SenseUnit, nInstFlag::STALL),      // and want to keep stats, also add
242     tInstLibEntry<tMethod>("sense-m100", &cHardwareCPU::Inst_SenseMult100, nInstFlag::STALL),   // the names to cStats::cStats() @JEB
243     tInstLibEntry<tMethod>("sense-resource-id", &cHardwareCPU::Inst_SenseResourceID, nInstFlag::STALL),
244     tInstLibEntry<tMethod>("sense-opinion-resource-quantity", &cHardwareCPU::Inst_SenseOpinionResourceQuantity, nInstFlag::STALL),
245     tInstLibEntry<tMethod>("sense-next-res-level", &cHardwareCPU::Inst_SenseNextResLevel, nInstFlag::STALL),
246     tInstLibEntry<tMethod>("sense-diff-faced", &cHardwareCPU::Inst_SenseDiffFaced, nInstFlag::STALL),
247     tInstLibEntry<tMethod>("sense-faced-habitat", &cHardwareCPU::Inst_SenseFacedHabitat, nInstFlag::STALL),
248 
249     tInstLibEntry<tMethod>("sense-resource0", &cHardwareCPU::Inst_SenseResource0, nInstFlag::STALL),
250     tInstLibEntry<tMethod>("sense-resource1", &cHardwareCPU::Inst_SenseResource1, nInstFlag::STALL),
251     tInstLibEntry<tMethod>("sense-resource2", &cHardwareCPU::Inst_SenseResource2, nInstFlag::STALL),
252     tInstLibEntry<tMethod>("sense-faced-resource0", &cHardwareCPU::Inst_SenseFacedResource0, nInstFlag::STALL),
253     tInstLibEntry<tMethod>("sense-faced-resource1", &cHardwareCPU::Inst_SenseFacedResource1, nInstFlag::STALL),
254     tInstLibEntry<tMethod>("sense-faced-resource2", &cHardwareCPU::Inst_SenseFacedResource2, nInstFlag::STALL),
255 
256     tInstLibEntry<tMethod>("if-resources", &cHardwareCPU::Inst_IfResources, nInstFlag::STALL),
257     tInstLibEntry<tMethod>("collect", &cHardwareCPU::Inst_Collect, nInstFlag::STALL),
258     tInstLibEntry<tMethod>("collect-no-env-remove", &cHardwareCPU::Inst_CollectNoEnvRemove, nInstFlag::STALL),
259     tInstLibEntry<tMethod>("destroy", &cHardwareCPU::Inst_Destroy, nInstFlag::STALL),
260     tInstLibEntry<tMethod>("nop-collect", &cHardwareCPU::Inst_NopCollect),
261     tInstLibEntry<tMethod>("collect-unit-prob", &cHardwareCPU::Inst_CollectUnitProbabilistic, nInstFlag::STALL),
262     tInstLibEntry<tMethod>("collect-specific", &cHardwareCPU::Inst_CollectSpecific, nInstFlag::STALL),
263     tInstLibEntry<tMethod>("donate-specific", &cHardwareCPU::Inst_DonateSpecific, nInstFlag::STALL),
264     tInstLibEntry<tMethod>("check-faced-kin", &cHardwareCPU::Inst_CheckFacedKin, nInstFlag::STALL),
265     tInstLibEntry<tMethod>("beg", &cHardwareCPU::Inst_SetBeggar, nInstFlag::STALL),
266     tInstLibEntry<tMethod>("check-beggar", &cHardwareCPU::Inst_CheckFacedBeggar, nInstFlag::STALL),
267     tInstLibEntry<tMethod>("if-faced-kin", &cHardwareCPU::Inst_IfFacedKin, nInstFlag::STALL),
268     tInstLibEntry<tMethod>("if-beggar", &cHardwareCPU::Inst_IfFacedBeggar, nInstFlag::STALL),
269     tInstLibEntry<tMethod>("if-beggar-needs-resource",&cHardwareCPU::Inst_IfFacedBeggarAndNeedResource, nInstFlag::STALL),
270     tInstLibEntry<tMethod>("if-beggar-kin",&cHardwareCPU::Inst_IfFacedBeggarAndKin, nInstFlag::STALL),
271     tInstLibEntry<tMethod>("if-kin-needs-resource",&cHardwareCPU::Inst_IfFacedKinAndNeedResource, nInstFlag::STALL),
272     tInstLibEntry<tMethod>("if-needs-resource",&cHardwareCPU::Inst_IfFacedNeedResource, nInstFlag::STALL),
273     tInstLibEntry<tMethod>("if-kin-beggar-needs-resource",&cHardwareCPU::Inst_IfFacedKinAndBeggarAndNeedResource, nInstFlag::STALL),
274     tInstLibEntry<tMethod>("if-kin-beggar-needs-resource-donate",&cHardwareCPU::Inst_IfFacedKinAndBeggarAndNeedResourceThenDonate, nInstFlag::STALL),
275     tInstLibEntry<tMethod>("if-beggar-needs-resource-donate",&cHardwareCPU::Inst_IfFacedBeggarANdNeedsResourceThenDonate, nInstFlag::STALL),
276     tInstLibEntry<tMethod>("fail-if-empty",&cHardwareCPU::Inst_FailIfEmpty, nInstFlag::STALL),
277 
278 
279     tInstLibEntry<tMethod>("donate-rnd", &cHardwareCPU::Inst_DonateRandom),
280     tInstLibEntry<tMethod>("donate-kin", &cHardwareCPU::Inst_DonateKin),
281     tInstLibEntry<tMethod>("donate-edt", &cHardwareCPU::Inst_DonateEditDist),
282     tInstLibEntry<tMethod>("donate-gbg",  &cHardwareCPU::Inst_DonateGreenBeardGene),
283     tInstLibEntry<tMethod>("donate-tgb",  &cHardwareCPU::Inst_DonateTrueGreenBeard),
284     tInstLibEntry<tMethod>("donate-shadedgb",  &cHardwareCPU::Inst_DonateShadedGreenBeard),
285     tInstLibEntry<tMethod>("donate-threshgb",  &cHardwareCPU::Inst_DonateThreshGreenBeard),
286     tInstLibEntry<tMethod>("donate-quantagb",  &cHardwareCPU::Inst_DonateQuantaThreshGreenBeard),
287     tInstLibEntry<tMethod>("donate-gbsl",  &cHardwareCPU::Inst_DonateGreenBeardSameLocus),
288     tInstLibEntry<tMethod>("donate-NUL", &cHardwareCPU::Inst_DonateNULL),
289     tInstLibEntry<tMethod>("donate-facing", &cHardwareCPU::Inst_DonateFacing),
290     tInstLibEntry<tMethod>("receive-donated-energy", &cHardwareCPU::Inst_ReceiveDonatedEnergy, nInstFlag::STALL),
291     tInstLibEntry<tMethod>("donate-energy", &cHardwareCPU::Inst_DonateEnergy, nInstFlag::STALL),
292     tInstLibEntry<tMethod>("update-metabolic-rate", &cHardwareCPU::Inst_UpdateMetabolicRate, nInstFlag::STALL),
293     tInstLibEntry<tMethod>("donate-energy-faced", &cHardwareCPU::Inst_DonateEnergyFaced, nInstFlag::STALL),
294     tInstLibEntry<tMethod>("donate-energy-faced1", &cHardwareCPU::Inst_DonateEnergyFaced1, nInstFlag::STALL),
295     tInstLibEntry<tMethod>("donate-energy-faced2", &cHardwareCPU::Inst_DonateEnergyFaced2, nInstFlag::STALL),
296     tInstLibEntry<tMethod>("donate-energy-faced5", &cHardwareCPU::Inst_DonateEnergyFaced5, nInstFlag::STALL),
297     tInstLibEntry<tMethod>("donate-energy-faced10", &cHardwareCPU::Inst_DonateEnergyFaced10, nInstFlag::STALL),
298     tInstLibEntry<tMethod>("donate-energy-faced20", &cHardwareCPU::Inst_DonateEnergyFaced20, nInstFlag::STALL),
299     tInstLibEntry<tMethod>("donate-energy-faced50", &cHardwareCPU::Inst_DonateEnergyFaced50, nInstFlag::STALL),
300     tInstLibEntry<tMethod>("donate-energy-faced100", &cHardwareCPU::Inst_DonateEnergyFaced100, nInstFlag::STALL),
301     tInstLibEntry<tMethod>("rotate-to-most-needy", &cHardwareCPU::Inst_RotateToMostNeedy, nInstFlag::STALL),
302     tInstLibEntry<tMethod>("request-energy", &cHardwareCPU::Inst_RequestEnergy, nInstFlag::STALL),
303     tInstLibEntry<tMethod>("request-energy-on", &cHardwareCPU::Inst_RequestEnergyFlagOn, nInstFlag::STALL),
304     tInstLibEntry<tMethod>("request-energy-off", &cHardwareCPU::Inst_RequestEnergyFlagOff, nInstFlag::STALL),
305     tInstLibEntry<tMethod>("increase-energy-donation", &cHardwareCPU::Inst_IncreaseEnergyDonation, nInstFlag::STALL),
306     tInstLibEntry<tMethod>("decrease-energy-donation", &cHardwareCPU::Inst_DecreaseEnergyDonation, nInstFlag::STALL),
307     tInstLibEntry<tMethod>("donate-resource0", &cHardwareCPU::Inst_DonateResource0, nInstFlag::STALL),
308     tInstLibEntry<tMethod>("donate-resource1", &cHardwareCPU::Inst_DonateResource1, nInstFlag::STALL),
309     tInstLibEntry<tMethod>("donate-resource2", &cHardwareCPU::Inst_DonateResource2, nInstFlag::STALL),
310     tInstLibEntry<tMethod>("IObuf-add1", &cHardwareCPU::Inst_IOBufAdd1, nInstFlag::STALL),
311     tInstLibEntry<tMethod>("IObuf-add0", &cHardwareCPU::Inst_IOBufAdd0, nInstFlag::STALL),
312 
313     tInstLibEntry<tMethod>("rotate-l", &cHardwareCPU::Inst_RotateL, nInstFlag::STALL),
314     tInstLibEntry<tMethod>("rotate-r", &cHardwareCPU::Inst_RotateR, nInstFlag::STALL),
315     tInstLibEntry<tMethod>("rotate-left-one", &cHardwareCPU::Inst_RotateLeftOne, nInstFlag::STALL),
316     tInstLibEntry<tMethod>("rotate-right-one", &cHardwareCPU::Inst_RotateRightOne, nInstFlag::STALL),
317     tInstLibEntry<tMethod>("rotate-label", &cHardwareCPU::Inst_RotateLabel, nInstFlag::STALL),
318     tInstLibEntry<tMethod>("rotate-to-unoccupied-cell", &cHardwareCPU::Inst_RotateUnoccupiedCell, nInstFlag::STALL),
319     tInstLibEntry<tMethod>("rotate-to-next-unoccupied-cell", &cHardwareCPU::Inst_RotateNextUnoccupiedCell, nInstFlag::STALL),
320     tInstLibEntry<tMethod>("rotate-to-occupied-cell", &cHardwareCPU::Inst_RotateOccupiedCell, nInstFlag::STALL),
321     tInstLibEntry<tMethod>("rotate-to-next-occupied-cell", &cHardwareCPU::Inst_RotateNextOccupiedCell, nInstFlag::STALL),
322     tInstLibEntry<tMethod>("rotate-to-event-cell", &cHardwareCPU::Inst_RotateEventCell, nInstFlag::STALL),
323     tInstLibEntry<tMethod>("rotate-uphill", &cHardwareCPU::Inst_RotateUphill, nInstFlag::STALL),
324     tInstLibEntry<tMethod>("rotate-home", &cHardwareCPU::Inst_RotateHome, nInstFlag::STALL),
325 
326     tInstLibEntry<tMethod>("set-cmut", &cHardwareCPU::Inst_SetCopyMut),
327     tInstLibEntry<tMethod>("mod-cmut", &cHardwareCPU::Inst_ModCopyMut),
328     tInstLibEntry<tMethod>("get-cell-xy", &cHardwareCPU::Inst_GetCellPosition),
329     tInstLibEntry<tMethod>("get-cell-x", &cHardwareCPU::Inst_GetCellPositionX),
330     tInstLibEntry<tMethod>("get-cell-y", &cHardwareCPU::Inst_GetCellPositionY),
331     tInstLibEntry<tMethod>("dist-from-diag", &cHardwareCPU::Inst_GetDistanceFromDiagonal),
332     tInstLibEntry<tMethod>("get-north-offset", &cHardwareCPU::Inst_GetDirectionOffNorth),
333     tInstLibEntry<tMethod>("get-northerly", &cHardwareCPU::Inst_GetNortherly),
334     tInstLibEntry<tMethod>("get-easterly", &cHardwareCPU::Inst_GetEasterly),
335     tInstLibEntry<tMethod>("zero-easterly", &cHardwareCPU::Inst_ZeroEasterly),
336     tInstLibEntry<tMethod>("zero-northerly", &cHardwareCPU::Inst_ZeroNortherly),
337 
338 
339     // State Grid instructions
340     tInstLibEntry<tMethod>("sg-move", &cHardwareCPU::Inst_SGMove),
341     tInstLibEntry<tMethod>("sg-rotate-l", &cHardwareCPU::Inst_SGRotateL),
342     tInstLibEntry<tMethod>("sg-rotate-r", &cHardwareCPU::Inst_SGRotateR),
343     tInstLibEntry<tMethod>("sg-sense", &cHardwareCPU::Inst_SGSense),
344 
345 
346 
347     // Movement instructions
348     tInstLibEntry<tMethod>("tumble", &cHardwareCPU::Inst_Tumble, nInstFlag::STALL),
349     tInstLibEntry<tMethod>("move", &cHardwareCPU::Inst_Move, nInstFlag::STALL),
350     tInstLibEntry<tMethod>("move-to-event", &cHardwareCPU::Inst_MoveToEvent, nInstFlag::STALL),
351     tInstLibEntry<tMethod>("if-event-in-unoccupied-neighbor-cell", &cHardwareCPU::Inst_IfNeighborEventInUnoccupiedCell),
352     tInstLibEntry<tMethod>("if-event-in-faced-cell", &cHardwareCPU::Inst_IfFacingEventCell),
353     tInstLibEntry<tMethod>("if-event-in-current-cell", &cHardwareCPU::Inst_IfEventInCell),
354 
355     // Threading instructions
356     tInstLibEntry<tMethod>("fork-th", &cHardwareCPU::Inst_ForkThread),
357     tInstLibEntry<tMethod>("forkl", &cHardwareCPU::Inst_ForkThreadLabel),
358     tInstLibEntry<tMethod>("forkl!=0", &cHardwareCPU::Inst_ForkThreadLabelIfNot0),
359     tInstLibEntry<tMethod>("forkl=0", &cHardwareCPU::Inst_ForkThreadLabelIf0),
360     tInstLibEntry<tMethod>("kill-th", &cHardwareCPU::Inst_KillThread),
361     tInstLibEntry<tMethod>("id-th", &cHardwareCPU::Inst_ThreadID),
362 
363     // Head-based instructions
364     tInstLibEntry<tMethod>("h-alloc", &cHardwareCPU::Inst_MaxAlloc, nInstFlag::DEFAULT, "Allocate maximum allowed space"),
365     tInstLibEntry<tMethod>("h-alloc-mw", &cHardwareCPU::Inst_MaxAllocMoveWriteHead),
366     tInstLibEntry<tMethod>("h-divide", &cHardwareCPU::Inst_HeadDivide, nInstFlag::DEFAULT | nInstFlag::STALL, "Divide code between read and write heads."),
367     tInstLibEntry<tMethod>("h-divide1RS", &cHardwareCPU::Inst_HeadDivide1RS, nInstFlag::STALL, "Divide code between read and write heads, at most one mutation on divide, resample if reverted."),
368     tInstLibEntry<tMethod>("h-divide2RS", &cHardwareCPU::Inst_HeadDivide2RS, nInstFlag::STALL, "Divide code between read and write heads, at most two mutations on divide, resample if reverted."),
369     tInstLibEntry<tMethod>("h-divideRS", &cHardwareCPU::Inst_HeadDivideRS, nInstFlag::STALL, "Divide code between read and write heads, resample if reverted."),
370     tInstLibEntry<tMethod>("h-read", &cHardwareCPU::Inst_HeadRead),
371     tInstLibEntry<tMethod>("h-write", &cHardwareCPU::Inst_HeadWrite),
372     tInstLibEntry<tMethod>("h-copy", &cHardwareCPU::Inst_HeadCopy, nInstFlag::DEFAULT, "Copy from read-head to write-head; advance both"),
373     tInstLibEntry<tMethod>("h-search", &cHardwareCPU::Inst_HeadSearch, nInstFlag::DEFAULT, "Find complement template and make with flow head"),
374     tInstLibEntry<tMethod>("h-search-direct", &cHardwareCPU::Inst_HeadSearchDirect, 0, "Find direct template and move the flow head"),
375     tInstLibEntry<tMethod>("h-push", &cHardwareCPU::Inst_HeadPush),
376     tInstLibEntry<tMethod>("h-pop", &cHardwareCPU::Inst_HeadPop),
377     tInstLibEntry<tMethod>("set-head", &cHardwareCPU::Inst_SetHead),
378     tInstLibEntry<tMethod>("adv-head", &cHardwareCPU::Inst_AdvanceHead),
379     tInstLibEntry<tMethod>("mov-head", &cHardwareCPU::Inst_MoveHead, nInstFlag::DEFAULT, "Move head ?IP? to the flow head"),
380     tInstLibEntry<tMethod>("jmp-head", &cHardwareCPU::Inst_JumpHead, nInstFlag::DEFAULT, "Move head ?IP? by amount in CX register; CX = old pos."),
381     tInstLibEntry<tMethod>("get-head", &cHardwareCPU::Inst_GetHead, nInstFlag::DEFAULT, "Copy the position of the ?IP? head into CX"),
382     tInstLibEntry<tMethod>("if-label", &cHardwareCPU::Inst_IfLabel, nInstFlag::DEFAULT, "Execute next if we copied complement of attached label"),
383     tInstLibEntry<tMethod>("if-label-direct", &cHardwareCPU::Inst_IfLabelDirect, nInstFlag::DEFAULT, "Execute next if we copied direct match of the attached label"),
384     tInstLibEntry<tMethod>("if-label2", &cHardwareCPU::Inst_IfLabel2, 0, "If copied label compl., exec next inst; else SKIP W/NOPS"),
385     tInstLibEntry<tMethod>("set-flow", &cHardwareCPU::Inst_SetFlow, nInstFlag::DEFAULT, "Set flow-head to position in ?CX?"),
386 
387     tInstLibEntry<tMethod>("res-mov-head", &cHardwareCPU::Inst_ResMoveHead, nInstFlag::STALL, "Move head ?IP? to the flow head depending on resource level"),
388     tInstLibEntry<tMethod>("res-jmp-head", &cHardwareCPU::Inst_ResJumpHead, nInstFlag::STALL, "Move head ?IP? by amount in CX register depending on resource level; CX = old pos."),
389 
390     tInstLibEntry<tMethod>("h-copy2", &cHardwareCPU::Inst_HeadCopy2),
391     tInstLibEntry<tMethod>("h-copy3", &cHardwareCPU::Inst_HeadCopy3),
392     tInstLibEntry<tMethod>("h-copy4", &cHardwareCPU::Inst_HeadCopy4),
393     tInstLibEntry<tMethod>("h-copy5", &cHardwareCPU::Inst_HeadCopy5),
394     tInstLibEntry<tMethod>("h-copy6", &cHardwareCPU::Inst_HeadCopy6),
395     tInstLibEntry<tMethod>("h-copy7", &cHardwareCPU::Inst_HeadCopy7),
396     tInstLibEntry<tMethod>("h-copy8", &cHardwareCPU::Inst_HeadCopy8),
397     tInstLibEntry<tMethod>("h-copy9", &cHardwareCPU::Inst_HeadCopy9),
398     tInstLibEntry<tMethod>("h-copy10", &cHardwareCPU::Inst_HeadCopy10),
399 
400     tInstLibEntry<tMethod>("divide-sex", &cHardwareCPU::Inst_HeadDivideSex, nInstFlag::STALL),
401     tInstLibEntry<tMethod>("divide-asex", &cHardwareCPU::Inst_HeadDivideAsex, nInstFlag::STALL),
402 
403     tInstLibEntry<tMethod>("div-sex", &cHardwareCPU::Inst_HeadDivideSex, nInstFlag::STALL),
404     tInstLibEntry<tMethod>("div-asex", &cHardwareCPU::Inst_HeadDivideAsex, nInstFlag::STALL),
405     tInstLibEntry<tMethod>("div-asex-w", &cHardwareCPU::Inst_HeadDivideAsexWait, nInstFlag::STALL),
406     tInstLibEntry<tMethod>("div-sex-MS", &cHardwareCPU::Inst_HeadDivideMateSelect, nInstFlag::STALL),
407 
408     tInstLibEntry<tMethod>("h-divide1", &cHardwareCPU::Inst_HeadDivide1, nInstFlag::STALL),
409     tInstLibEntry<tMethod>("h-divide2", &cHardwareCPU::Inst_HeadDivide2, nInstFlag::STALL),
410     tInstLibEntry<tMethod>("h-divide3", &cHardwareCPU::Inst_HeadDivide3, nInstFlag::STALL),
411     tInstLibEntry<tMethod>("h-divide4", &cHardwareCPU::Inst_HeadDivide4, nInstFlag::STALL),
412     tInstLibEntry<tMethod>("h-divide5", &cHardwareCPU::Inst_HeadDivide5, nInstFlag::STALL),
413     tInstLibEntry<tMethod>("h-divide6", &cHardwareCPU::Inst_HeadDivide6, nInstFlag::STALL),
414     tInstLibEntry<tMethod>("h-divide7", &cHardwareCPU::Inst_HeadDivide7, nInstFlag::STALL),
415     tInstLibEntry<tMethod>("h-divide8", &cHardwareCPU::Inst_HeadDivide8, nInstFlag::STALL),
416     tInstLibEntry<tMethod>("h-divide9", &cHardwareCPU::Inst_HeadDivide9, nInstFlag::STALL),
417     tInstLibEntry<tMethod>("h-divide10", &cHardwareCPU::Inst_HeadDivide10, nInstFlag::STALL),
418     tInstLibEntry<tMethod>("h-divide16", &cHardwareCPU::Inst_HeadDivide16, nInstFlag::STALL),
419     tInstLibEntry<tMethod>("h-divide32", &cHardwareCPU::Inst_HeadDivide32, nInstFlag::STALL),
420     tInstLibEntry<tMethod>("h-divide50", &cHardwareCPU::Inst_HeadDivide50, nInstFlag::STALL),
421     tInstLibEntry<tMethod>("h-divide100", &cHardwareCPU::Inst_HeadDivide100, nInstFlag::STALL),
422     tInstLibEntry<tMethod>("h-divide500", &cHardwareCPU::Inst_HeadDivide500, nInstFlag::STALL),
423     tInstLibEntry<tMethod>("h-divide1000", &cHardwareCPU::Inst_HeadDivide1000, nInstFlag::STALL),
424     tInstLibEntry<tMethod>("h-divide5000", &cHardwareCPU::Inst_HeadDivide5000, nInstFlag::STALL),
425     tInstLibEntry<tMethod>("h-divide10000", &cHardwareCPU::Inst_HeadDivide10000, nInstFlag::STALL),
426     tInstLibEntry<tMethod>("h-divide50000", &cHardwareCPU::Inst_HeadDivide50000, nInstFlag::STALL),
427     tInstLibEntry<tMethod>("h-divide0.5", &cHardwareCPU::Inst_HeadDivide0_5, nInstFlag::STALL),
428     tInstLibEntry<tMethod>("h-divide0.1", &cHardwareCPU::Inst_HeadDivide0_1, nInstFlag::STALL),
429     tInstLibEntry<tMethod>("h-divide0.05", &cHardwareCPU::Inst_HeadDivide0_05, nInstFlag::STALL),
430     tInstLibEntry<tMethod>("h-divide0.01", &cHardwareCPU::Inst_HeadDivide0_01, nInstFlag::STALL),
431     tInstLibEntry<tMethod>("h-divide0.001", &cHardwareCPU::Inst_HeadDivide0_001, nInstFlag::STALL),
432 
433     //@CHC Mating type / mate choice instructions
434     tInstLibEntry<tMethod>("set-mating-type-male", &cHardwareCPU::Inst_SetMatingTypeMale),
435     tInstLibEntry<tMethod>("set-mating-type-female", &cHardwareCPU::Inst_SetMatingTypeFemale),
436     tInstLibEntry<tMethod>("set-mating-type-juvenile", &cHardwareCPU::Inst_SetMatingTypeJuvenile),
437     tInstLibEntry<tMethod>("div-sex-mating-type", &cHardwareCPU::Inst_DivideSexMatingType, nInstFlag::STALL),
438     tInstLibEntry<tMethod>("if-mating-type-male", &cHardwareCPU::Inst_IfMatingTypeMale),
439     tInstLibEntry<tMethod>("if-mating-type-female", &cHardwareCPU::Inst_IfMatingTypeFemale),
440     tInstLibEntry<tMethod>("if-mating-type-juvenile", &cHardwareCPU::Inst_IfMatingTypeJuvenile),
441     tInstLibEntry<tMethod>("increment-mating-display-a", &cHardwareCPU::Inst_IncrementMatingDisplayA),
442     tInstLibEntry<tMethod>("increment-mating-display-b", &cHardwareCPU::Inst_IncrementMatingDisplayB),
443     tInstLibEntry<tMethod>("set-mating-display-a", &cHardwareCPU::Inst_SetMatingDisplayA),
444     tInstLibEntry<tMethod>("set-mating-display-b", &cHardwareCPU::Inst_SetMatingDisplayB),
445     tInstLibEntry<tMethod>("set-mate-preference-random", &cHardwareCPU::Inst_SetMatePreferenceRandom),
446     tInstLibEntry<tMethod>("set-mate-preference-highest-display-a", &cHardwareCPU::Inst_SetMatePreferenceHighestDisplayA),
447     tInstLibEntry<tMethod>("set-mate-preference-highest-display-b", &cHardwareCPU::Inst_SetMatePreferenceHighestDisplayB),
448     tInstLibEntry<tMethod>("set-mate-preference-highest-merit", &cHardwareCPU::Inst_SetMatePreferenceHighestMerit),
449 
450 
451     // High-level instructions
452     tInstLibEntry<tMethod>("repro_deme", &cHardwareCPU::Inst_ReproDeme, nInstFlag::STALL),
453     tInstLibEntry<tMethod>("repro", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
454     tInstLibEntry<tMethod>("repro-sex", &cHardwareCPU::Inst_ReproSex, nInstFlag::STALL),
455     tInstLibEntry<tMethod>("repro-germ-flag", &cHardwareCPU::Inst_ReproGermFlag, nInstFlag::STALL),
456     tInstLibEntry<tMethod>("repro-A", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
457     tInstLibEntry<tMethod>("repro-B", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
458     tInstLibEntry<tMethod>("repro-C", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
459     tInstLibEntry<tMethod>("repro-D", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
460     tInstLibEntry<tMethod>("repro-E", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
461     tInstLibEntry<tMethod>("repro-F", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
462     tInstLibEntry<tMethod>("repro-G", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
463     tInstLibEntry<tMethod>("repro-H", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
464     tInstLibEntry<tMethod>("repro-I", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
465     tInstLibEntry<tMethod>("repro-J", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
466     tInstLibEntry<tMethod>("repro-K", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
467     tInstLibEntry<tMethod>("repro-L", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
468     tInstLibEntry<tMethod>("repro-M", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
469     tInstLibEntry<tMethod>("repro-N", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
470     tInstLibEntry<tMethod>("repro-O", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
471     tInstLibEntry<tMethod>("repro-P", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
472     tInstLibEntry<tMethod>("repro-Q", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
473     tInstLibEntry<tMethod>("repro-R", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
474     tInstLibEntry<tMethod>("repro-S", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
475     tInstLibEntry<tMethod>("repro-T", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
476     tInstLibEntry<tMethod>("repro-U", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
477     tInstLibEntry<tMethod>("repro-V", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
478     tInstLibEntry<tMethod>("repro-W", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
479     tInstLibEntry<tMethod>("repro-X", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
480     tInstLibEntry<tMethod>("repro-Y", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
481     tInstLibEntry<tMethod>("repro-Z", &cHardwareCPU::Inst_Repro, nInstFlag::STALL),
482     tInstLibEntry<tMethod>("cond-repro", &cHardwareCPU::Inst_ConditionalRepro, nInstFlag::STALL),
483 
484     tInstLibEntry<tMethod>("put-repro", &cHardwareCPU::Inst_TaskPutRepro, nInstFlag::STALL),
485     tInstLibEntry<tMethod>("metabolize", &cHardwareCPU::Inst_TaskPutResetInputsRepro, nInstFlag::STALL),
486 
487     tInstLibEntry<tMethod>("sterilize", &cHardwareCPU::Inst_Sterilize),
488 
489     tInstLibEntry<tMethod>("spawn-deme", &cHardwareCPU::Inst_SpawnDeme, nInstFlag::STALL),
490 
491     // Suicide
492     tInstLibEntry<tMethod>("kazi",	&cHardwareCPU::Inst_Kazi, nInstFlag::STALL),
493     tInstLibEntry<tMethod>("kazi5", &cHardwareCPU::Inst_Kazi5, nInstFlag::STALL),
494     tInstLibEntry<tMethod>("die", &cHardwareCPU::Inst_Die, nInstFlag::STALL),
495     tInstLibEntry<tMethod>("poison", &cHardwareCPU::Inst_Poison),
496     tInstLibEntry<tMethod>("suicide", &cHardwareCPU::Inst_Suicide, nInstFlag::STALL),
497     tInstLibEntry<tMethod>("relinquishEnergyToFutureDeme", &cHardwareCPU::Inst_RelinquishEnergyToFutureDeme, nInstFlag::STALL),
498     tInstLibEntry<tMethod>("relinquishEnergyToNeighborOrganisms", &cHardwareCPU::Inst_RelinquishEnergyToNeighborOrganisms, nInstFlag::STALL),
499     tInstLibEntry<tMethod>("relinquishEnergyToOrganismsInDeme", &cHardwareCPU::Inst_RelinquishEnergyToOrganismsInDeme, nInstFlag::STALL),
500 
501     // Energy level detection
502     tInstLibEntry<tMethod>("if-energy-low", &cHardwareCPU::Inst_IfEnergyLow, nInstFlag::STALL),
503     tInstLibEntry<tMethod>("if-energy-not-low", &cHardwareCPU::Inst_IfEnergyNotLow, nInstFlag::STALL),
504     tInstLibEntry<tMethod>("if-faced-energy-low", &cHardwareCPU::Inst_IfFacedEnergyLow, nInstFlag::STALL),
505     tInstLibEntry<tMethod>("if-faced-energy-not-low", &cHardwareCPU::Inst_IfFacedEnergyNotLow, nInstFlag::STALL),
506     tInstLibEntry<tMethod>("if-energy-high", &cHardwareCPU::Inst_IfEnergyHigh, nInstFlag::STALL),
507     tInstLibEntry<tMethod>("if-energy-not-high", &cHardwareCPU::Inst_IfEnergyNotHigh, nInstFlag::STALL),
508     tInstLibEntry<tMethod>("if-faced-energy-high", &cHardwareCPU::Inst_IfFacedEnergyHigh, nInstFlag::STALL),
509     tInstLibEntry<tMethod>("if-faced-energy-not-high", &cHardwareCPU::Inst_IfFacedEnergyNotHigh, nInstFlag::STALL),
510     tInstLibEntry<tMethod>("if-energy-med", &cHardwareCPU::Inst_IfEnergyMed, nInstFlag::STALL),
511     tInstLibEntry<tMethod>("if-faced-energy-med", &cHardwareCPU::Inst_IfFacedEnergyMed, nInstFlag::STALL),
512     tInstLibEntry<tMethod>("if-faced-energy-less", &cHardwareCPU::Inst_IfFacedEnergyLess, nInstFlag::STALL),
513     tInstLibEntry<tMethod>("if-faced-energy-more", &cHardwareCPU::Inst_IfFacedEnergyMore, nInstFlag::STALL),
514     tInstLibEntry<tMethod>("if-energy-in-buffer", &cHardwareCPU::Inst_IfEnergyInBuffer, nInstFlag::STALL),
515     tInstLibEntry<tMethod>("if-energy-not-in-buffer", &cHardwareCPU::Inst_IfEnergyNotInBuffer, nInstFlag::STALL),
516     tInstLibEntry<tMethod>("get-energy-level", &cHardwareCPU::Inst_GetEnergyLevel, nInstFlag::STALL),
517     tInstLibEntry<tMethod>("get-faced-energy-level", &cHardwareCPU::Inst_GetFacedEnergyLevel, nInstFlag::STALL),
518     tInstLibEntry<tMethod>("if-faced-request-on", &cHardwareCPU::Inst_IfFacedEnergyRequestOn, nInstFlag::STALL),
519     tInstLibEntry<tMethod>("if-faced-request-off", &cHardwareCPU::Inst_IfFacedEnergyRequestOff, nInstFlag::STALL),
520     tInstLibEntry<tMethod>("get-energy-request-status", &cHardwareCPU::Inst_GetEnergyRequestStatus, nInstFlag::STALL),
521     tInstLibEntry<tMethod>("get-faced-energy-request-status", &cHardwareCPU::Inst_GetFacedEnergyRequestStatus, nInstFlag::STALL),
522 
523 
524     // Sleep and time
525     tInstLibEntry<tMethod>("sleep", &cHardwareCPU::Inst_Sleep, nInstFlag::STALL | nInstFlag::SLEEP),
526     tInstLibEntry<tMethod>("sleep1", &cHardwareCPU::Inst_Sleep, nInstFlag::STALL | nInstFlag::SLEEP),
527     tInstLibEntry<tMethod>("sleep2", &cHardwareCPU::Inst_Sleep, nInstFlag::STALL | nInstFlag::SLEEP),
528     tInstLibEntry<tMethod>("sleep3", &cHardwareCPU::Inst_Sleep, nInstFlag::STALL | nInstFlag::SLEEP),
529     tInstLibEntry<tMethod>("sleep4", &cHardwareCPU::Inst_Sleep, nInstFlag::STALL | nInstFlag::SLEEP),
530     tInstLibEntry<tMethod>("time", &cHardwareCPU::Inst_GetUpdate, nInstFlag::STALL),
531 
532     // Promoter Model
533     tInstLibEntry<tMethod>("promoter", &cHardwareCPU::Inst_Promoter),
534     tInstLibEntry<tMethod>("terminate", &cHardwareCPU::Inst_Terminate),
535     tInstLibEntry<tMethod>("regulate", &cHardwareCPU::Inst_Regulate),
536     tInstLibEntry<tMethod>("regulate-sp", &cHardwareCPU::Inst_RegulateSpecificPromoters),
537     tInstLibEntry<tMethod>("s-regulate", &cHardwareCPU::Inst_SenseRegulate),
538     tInstLibEntry<tMethod>("numberate", &cHardwareCPU::Inst_Numberate),
539     tInstLibEntry<tMethod>("numberate-24", &cHardwareCPU::Inst_Numberate24),
540 
541     // Bit Consensus
542     tInstLibEntry<tMethod>("bit-cons", &cHardwareCPU::Inst_BitConsensus),
543     tInstLibEntry<tMethod>("bit-cons-24", &cHardwareCPU::Inst_BitConsensus24),
544     tInstLibEntry<tMethod>("if-cons", &cHardwareCPU::Inst_IfConsensus, 0, "Execute next instruction if ?BX? in consensus, else skip it"),
545     tInstLibEntry<tMethod>("if-cons-24", &cHardwareCPU::Inst_IfConsensus24, 0, "Execute next instruction if ?BX[0:23]? in consensus , else skip it"),
546     tInstLibEntry<tMethod>("if-less-cons", &cHardwareCPU::Inst_IfLessConsensus, 0, "Execute next instruction if Count(?BX?) < Count(?CX?), else skip it"),
547     tInstLibEntry<tMethod>("if-less-cons-24", &cHardwareCPU::Inst_IfLessConsensus24, 0, "Execute next instruction if Count(?BX[0:23]?) < Count(?CX[0:23]?), else skip it"),
548 
549     // Bit Masking (higher order bit masking is possible, just add the instructions if needed)
550     tInstLibEntry<tMethod>("mask-signbit", &cHardwareCPU::Inst_MaskSignBit),
551     tInstLibEntry<tMethod>("maskoff-lower16bits", &cHardwareCPU::Inst_MaskOffLower16Bits),
552     tInstLibEntry<tMethod>("maskoff-lower16bits-defaultAX", &cHardwareCPU::Inst_MaskOffLower16Bits_defaultAX),
553     tInstLibEntry<tMethod>("maskoff-lower15bits", &cHardwareCPU::Inst_MaskOffLower15Bits),
554     tInstLibEntry<tMethod>("maskoff-lower15bits-defaultAX", &cHardwareCPU::Inst_MaskOffLower15Bits_defaultAX),
555     tInstLibEntry<tMethod>("maskoff-lower14bits", &cHardwareCPU::Inst_MaskOffLower14Bits),
556     tInstLibEntry<tMethod>("maskoff-lower14bits-defaultAX", &cHardwareCPU::Inst_MaskOffLower14Bits_defaultAX),
557     tInstLibEntry<tMethod>("maskoff-lower13bits", &cHardwareCPU::Inst_MaskOffLower13Bits),
558     tInstLibEntry<tMethod>("maskoff-lower13bits-defaultAX", &cHardwareCPU::Inst_MaskOffLower13Bits_defaultAX),
559     tInstLibEntry<tMethod>("maskoff-lower12bits", &cHardwareCPU::Inst_MaskOffLower12Bits),
560     tInstLibEntry<tMethod>("maskoff-lower12bits-defaultAX", &cHardwareCPU::Inst_MaskOffLower12Bits_defaultAX),
561     tInstLibEntry<tMethod>("maskoff-lower8bits",  &cHardwareCPU::Inst_MaskOffLower8Bits),
562     tInstLibEntry<tMethod>("maskoff-lower8bits-defaultAX",  &cHardwareCPU::Inst_MaskOffLower8Bits_defaultAX),
563     tInstLibEntry<tMethod>("maskoff-lower4bits",  &cHardwareCPU::Inst_MaskOffLower4Bits),
564     tInstLibEntry<tMethod>("maskoff-lower4bits-defaultAX",  &cHardwareCPU::Inst_MaskOffLower4Bits_defaultAX),
565 
566 
567     // Energy usage
568     tInstLibEntry<tMethod>("double-energy-usage", &cHardwareCPU::Inst_DoubleEnergyUsage, nInstFlag::STALL),
569     tInstLibEntry<tMethod>("halve-energy-usage", &cHardwareCPU::Inst_HalveEnergyUsage, nInstFlag::STALL),
570     tInstLibEntry<tMethod>("default-energy-usage", &cHardwareCPU::Inst_DefaultEnergyUsage, nInstFlag::STALL),
571 
572     // Messaging
573     tInstLibEntry<tMethod>("send-msg", &cHardwareCPU::Inst_SendMessage, nInstFlag::STALL),
574     tInstLibEntry<tMethod>("retrieve-msg", &cHardwareCPU::Inst_RetrieveMessage, nInstFlag::STALL),
575     tInstLibEntry<tMethod>("bcast1", &cHardwareCPU::Inst_Broadcast1, nInstFlag::STALL),
576     tInstLibEntry<tMethod>("bcast2", &cHardwareCPU::Inst_Broadcast2, nInstFlag::STALL),
577     tInstLibEntry<tMethod>("bcast4", &cHardwareCPU::Inst_Broadcast4, nInstFlag::STALL),
578     tInstLibEntry<tMethod>("bcast8", &cHardwareCPU::Inst_Broadcast8, nInstFlag::STALL),
579 
580     // Alarms
581     tInstLibEntry<tMethod>("send-alarm-msg-local", &cHardwareCPU::Inst_Alarm_MSG_local, nInstFlag::STALL),
582     tInstLibEntry<tMethod>("send-alarm-msg-multihop", &cHardwareCPU::Inst_Alarm_MSG_multihop, nInstFlag::STALL),
583     tInstLibEntry<tMethod>("send-alarm-msg-bit-cons24-local", &cHardwareCPU::Inst_Alarm_MSG_Bit_Cons24_local, nInstFlag::STALL),
584     tInstLibEntry<tMethod>("send-alarm-msg-bit-cons24-multihop", &cHardwareCPU::Inst_Alarm_MSG_Bit_Cons24_multihop, nInstFlag::STALL),
585     tInstLibEntry<tMethod>("alarm-label-high", &cHardwareCPU::Inst_Alarm_Label),
586     tInstLibEntry<tMethod>("alarm-label-low", &cHardwareCPU::Inst_Alarm_Label),
587 
588     // Interrupt
589     tInstLibEntry<tMethod>("send-msg-interrupt-type0", &cHardwareCPU::Inst_SendMessageInterruptType0, nInstFlag::STALL),
590     tInstLibEntry<tMethod>("send-msg-interrupt-type1", &cHardwareCPU::Inst_SendMessageInterruptType1, nInstFlag::STALL),
591     tInstLibEntry<tMethod>("send-msg-interrupt-type2", &cHardwareCPU::Inst_SendMessageInterruptType2, nInstFlag::STALL),
592     tInstLibEntry<tMethod>("send-msg-interrupt-type3", &cHardwareCPU::Inst_SendMessageInterruptType3, nInstFlag::STALL),
593     tInstLibEntry<tMethod>("send-msg-interrupt-type4", &cHardwareCPU::Inst_SendMessageInterruptType4, nInstFlag::STALL),
594     tInstLibEntry<tMethod>("send-msg-interrupt-type5", &cHardwareCPU::Inst_SendMessageInterruptType5, nInstFlag::STALL),
595     tInstLibEntry<tMethod>("msg-handler-type0", &cHardwareCPU::Inst_START_Handler),
596     tInstLibEntry<tMethod>("msg-handler-type1", &cHardwareCPU::Inst_START_Handler),
597     tInstLibEntry<tMethod>("msg-handler-type2", &cHardwareCPU::Inst_START_Handler),
598     tInstLibEntry<tMethod>("msg-handler-type3", &cHardwareCPU::Inst_START_Handler),
599     tInstLibEntry<tMethod>("msg-handler-type4", &cHardwareCPU::Inst_START_Handler),
600     tInstLibEntry<tMethod>("msg-handler-type5", &cHardwareCPU::Inst_START_Handler),
601     tInstLibEntry<tMethod>("moved-handler", &cHardwareCPU::Inst_START_Handler),
602     tInstLibEntry<tMethod>("end-handler", &cHardwareCPU::Inst_End_Handler),
603 
604     // Placebo instructions
605     tInstLibEntry<tMethod>("skip", &cHardwareCPU::Inst_Skip),
606 
607     // @BDC additions for pheromones
608     tInstLibEntry<tMethod>("phero-on", &cHardwareCPU::Inst_PheroOn),
609     tInstLibEntry<tMethod>("phero-off", &cHardwareCPU::Inst_PheroOff),
610     tInstLibEntry<tMethod>("pherotoggle", &cHardwareCPU::Inst_PheroToggle),
611     tInstLibEntry<tMethod>("sense-target", &cHardwareCPU::Inst_SenseTarget),
612     tInstLibEntry<tMethod>("sense-target-faced", &cHardwareCPU::Inst_SenseTargetFaced),
613     tInstLibEntry<tMethod>("sensef", &cHardwareCPU::Inst_SenseLog2Facing),
614     tInstLibEntry<tMethod>("sensef-unit", &cHardwareCPU::Inst_SenseUnitFacing),
615     tInstLibEntry<tMethod>("sensef-m100", &cHardwareCPU::Inst_SenseMult100Facing),
616     tInstLibEntry<tMethod>("sense-pheromone", &cHardwareCPU::Inst_SensePheromone),
617     tInstLibEntry<tMethod>("sense-pheromone-faced", &cHardwareCPU::Inst_SensePheromoneFaced),
618     tInstLibEntry<tMethod>("sense-pheromone-inDemeGlobal", &cHardwareCPU::Inst_SensePheromoneInDemeGlobal),
619     tInstLibEntry<tMethod>("sense-pheromone-global", &cHardwareCPU::Inst_SensePheromoneGlobal),
620     tInstLibEntry<tMethod>("sense-pheromone-global-defaultAX", &cHardwareCPU::Inst_SensePheromoneGlobal_defaultAX),
621     tInstLibEntry<tMethod>("exploit", &cHardwareCPU::Inst_Exploit, nInstFlag::STALL),
622     tInstLibEntry<tMethod>("exploit-forward5", &cHardwareCPU::Inst_ExploitForward5, nInstFlag::STALL),
623     tInstLibEntry<tMethod>("exploit-forward3", &cHardwareCPU::Inst_ExploitForward3, nInstFlag::STALL),
624     tInstLibEntry<tMethod>("explore", &cHardwareCPU::Inst_Explore, nInstFlag::STALL),
625     tInstLibEntry<tMethod>("movetarget", &cHardwareCPU::Inst_MoveTarget, nInstFlag::STALL),
626     tInstLibEntry<tMethod>("movetarget-forward5", &cHardwareCPU::Inst_MoveTargetForward5, nInstFlag::STALL),
627     tInstLibEntry<tMethod>("movetarget-forward3", &cHardwareCPU::Inst_MoveTargetForward3, nInstFlag::STALL),
628     tInstLibEntry<tMethod>("supermove", &cHardwareCPU::Inst_SuperMove, nInstFlag::STALL),
629     tInstLibEntry<tMethod>("if-target", &cHardwareCPU::Inst_IfTarget),
630     tInstLibEntry<tMethod>("if-not-target", &cHardwareCPU::Inst_IfNotTarget),
631     tInstLibEntry<tMethod>("if-pheromone", &cHardwareCPU::Inst_IfPheromone),
632     tInstLibEntry<tMethod>("if-not-pheromone", &cHardwareCPU::Inst_IfNotPheromone),
633     tInstLibEntry<tMethod>("drop-pheromone", &cHardwareCPU::Inst_DropPheromone, nInstFlag::STALL),
634 
635     // Opinion instructions.
636     // These are STALLs because opinions are only relevant with respect to time.
637     tInstLibEntry<tMethod>("set-opinion", &cHardwareCPU::Inst_SetOpinion, nInstFlag::STALL),
638     tInstLibEntry<tMethod>("get-opinion", &cHardwareCPU::Inst_GetOpinion, nInstFlag::STALL),
639     tInstLibEntry<tMethod>("get-opinionOnly", &cHardwareCPU::Inst_GetOpinionOnly_ZeroIfNone, nInstFlag::STALL),
640     tInstLibEntry<tMethod>("clear-opinion", &cHardwareCPU::Inst_ClearOpinion, nInstFlag::STALL),
641     tInstLibEntry<tMethod>("if-opinion-set", &cHardwareCPU::Inst_IfOpinionSet, nInstFlag::STALL),
642     tInstLibEntry<tMethod>("if-opinion-notset", &cHardwareCPU::Inst_IfOpinionNotSet, nInstFlag::STALL),
643     tInstLibEntry<tMethod>("set-opinion-0", &cHardwareCPU::Inst_SetOpinionToZero, nInstFlag::STALL),
644     tInstLibEntry<tMethod>("set-opinion-1", &cHardwareCPU::Inst_SetOpinionToOne, nInstFlag::STALL),
645     tInstLibEntry<tMethod>("set-opinion-2", &cHardwareCPU::Inst_SetOpinionToTwo, nInstFlag::STALL),
646 
647     // Data collection
648     tInstLibEntry<tMethod>("if-cell-data-changed", &cHardwareCPU::Inst_IfCellDataChanged, nInstFlag::STALL),
649     tInstLibEntry<tMethod>("collect-cell-data", &cHardwareCPU::Inst_CollectCellData, nInstFlag::STALL),
650     tInstLibEntry<tMethod>("kill-cell-event", &cHardwareCPU::Inst_KillCellEvent, nInstFlag::STALL),
651     tInstLibEntry<tMethod>("kill-faced-cell-event", &cHardwareCPU::Inst_KillFacedCellEvent, nInstFlag::STALL),
652     tInstLibEntry<tMethod>("collect-cell-data-and-kill-event", &cHardwareCPU::Inst_CollectCellDataAndKillEvent, nInstFlag::STALL),
653     tInstLibEntry<tMethod>("read-cell-data", &cHardwareCPU::Inst_ReadCellData),
654     tInstLibEntry<tMethod>("read-faced-cell-data", &cHardwareCPU::Inst_ReadFacedCellData, nInstFlag::STALL),
655     tInstLibEntry<tMethod>("read-faced-cell-org-id", &cHardwareCPU::Inst_ReadFacedCellDataOrgID, nInstFlag::STALL),
656     tInstLibEntry<tMethod>("read-faced-cell-freshness", &cHardwareCPU::Inst_ReadFacedCellDataFreshness, nInstFlag::STALL),
657     tInstLibEntry<tMethod>("mark-cell-with-id", &cHardwareCPU::Inst_MarkCellWithID),
658     tInstLibEntry<tMethod>("mark-cell-with-vitality", &cHardwareCPU::Inst_MarkCellWithVitality),
659     tInstLibEntry<tMethod>("get-res-stored", &cHardwareCPU::Inst_GetResStored),
660     tInstLibEntry<tMethod>("get-id", &cHardwareCPU::Inst_GetID),
661     tInstLibEntry<tMethod>("get-faced-vitality-diff", &cHardwareCPU::Inst_GetFacedVitalityDiff, nInstFlag::STALL),
662     tInstLibEntry<tMethod>("get-faced-org-id", &cHardwareCPU::Inst_GetFacedOrgID, nInstFlag::STALL),
663     tInstLibEntry<tMethod>("attack-faced-org", &cHardwareCPU::Inst_AttackFacedOrg, nInstFlag::STALL),
664     tInstLibEntry<tMethod>("get-attack-odds", &cHardwareCPU::Inst_GetAttackOdds, nInstFlag::STALL),
665 
666     // Synchronization
667     tInstLibEntry<tMethod>("flash", &cHardwareCPU::Inst_Flash, nInstFlag::STALL),
668     tInstLibEntry<tMethod>("if-recvd-flash", &cHardwareCPU::Inst_IfRecvdFlash, nInstFlag::STALL),
669     tInstLibEntry<tMethod>("flash-info", &cHardwareCPU::Inst_FlashInfo, nInstFlag::STALL),
670     tInstLibEntry<tMethod>("flash-info-b", &cHardwareCPU::Inst_FlashInfoB, nInstFlag::STALL),
671     tInstLibEntry<tMethod>("reset-flash-info", &cHardwareCPU::Inst_ResetFlashInfo, nInstFlag::STALL),
672     tInstLibEntry<tMethod>("hard-reset", &cHardwareCPU::Inst_HardReset, nInstFlag::STALL),
673     tInstLibEntry<tMethod>("get-cycles", &cHardwareCPU::Inst_GetCycles, nInstFlag::STALL),
674 
675     // Neighborhood-sensing instructions
676     tInstLibEntry<tMethod>("get-neighborhood", &cHardwareCPU::Inst_GetNeighborhood, nInstFlag::STALL),
677     tInstLibEntry<tMethod>("if-neighborhood-changed", &cHardwareCPU::Inst_IfNeighborhoodChanged, nInstFlag::STALL),
678 
679 
680     // Reputation instructions
681 
682     tInstLibEntry<tMethod>("donate-frm", &cHardwareCPU::Inst_DonateFacingRawMaterials, nInstFlag::STALL),
683     tInstLibEntry<tMethod>("donate-spec", &cHardwareCPU::Inst_DonateFacingRawMaterialsOtherSpecies, nInstFlag::STALL),
684     tInstLibEntry<tMethod>("donate-if-donor", &cHardwareCPU::Inst_DonateIfDonor, nInstFlag::STALL),
685     tInstLibEntry<tMethod>("donate-string", &cHardwareCPU::Inst_DonateFacingString, nInstFlag::STALL),
686 
687     tInstLibEntry<tMethod>("get-neighbors-reputation", &cHardwareCPU::Inst_GetNeighborsReputation, nInstFlag::STALL),
688     tInstLibEntry<tMethod>("get-reputation", &cHardwareCPU::Inst_GetReputation, nInstFlag::STALL),
689     tInstLibEntry<tMethod>("get-raw-mat-amount", &cHardwareCPU::Inst_GetAmountOfRawMaterials, nInstFlag::STALL),
690     tInstLibEntry<tMethod>("get-other-raw-mat-amount", &cHardwareCPU::Inst_GetAmountOfOtherRawMaterials, nInstFlag::STALL),
691     tInstLibEntry<tMethod>("pose", &cHardwareCPU::Inst_Pose, nInstFlag::STALL),
692     tInstLibEntry<tMethod>("rotate-to-rep", &cHardwareCPU::Inst_RotateToGreatestReputation, nInstFlag::STALL),
693     tInstLibEntry<tMethod>("rotate-to-rep-and-donate", &cHardwareCPU::Inst_RotateToGreatestReputationAndDonate, nInstFlag::STALL),
694     tInstLibEntry<tMethod>("rotate-to-rep-tag", &cHardwareCPU::Inst_RotateToGreatestReputationWithDifferentTag, nInstFlag::STALL),
695     tInstLibEntry<tMethod>("rotate-to-rep-lineage", &cHardwareCPU::Inst_RotateToGreatestReputationWithDifferentLineage, nInstFlag::STALL),
696     tInstLibEntry<tMethod>("rotate-to-tag", &cHardwareCPU::Inst_RotateToDifferentTag, nInstFlag::STALL),
697     tInstLibEntry<tMethod>("if-donor",  &cHardwareCPU::Inst_IfDonor, nInstFlag::STALL),
698     tInstLibEntry<tMethod>("prod-string",  &cHardwareCPU::Inst_ProduceString, nInstFlag::STALL),
699 
700     // Group formation instructions
701     tInstLibEntry<tMethod>("join-group", &cHardwareCPU::Inst_JoinGroup, nInstFlag::STALL),
702     tInstLibEntry<tMethod>("join-mt-group", &cHardwareCPU::Inst_JoinMTGroup, nInstFlag::STALL),
703     tInstLibEntry<tMethod>("join-next-group", &cHardwareCPU::Inst_JoinNextGroup, nInstFlag::STALL),
704     tInstLibEntry<tMethod>("join-next-mt-group", &cHardwareCPU::Inst_JoinMTGroup, nInstFlag::STALL),
705     tInstLibEntry<tMethod>("orgs-in-my-group", &cHardwareCPU::Inst_NumberOrgsInMyGroup, nInstFlag::STALL),
706     tInstLibEntry<tMethod>("num-mt-in-my-group", &cHardwareCPU::Inst_NumberMTInMyGroup, nInstFlag::STALL),
707     tInstLibEntry<tMethod>("orgs-in-group", &cHardwareCPU::Inst_NumberOrgsInGroup, nInstFlag::STALL),
708     tInstLibEntry<tMethod>("num-mt-in-group", &cHardwareCPU::Inst_NumberMTInGroup, nInstFlag::STALL),
709     tInstLibEntry<tMethod>("number-next-group", &cHardwareCPU::Inst_NumberNextGroup, nInstFlag::STALL),
710     tInstLibEntry<tMethod>("num-mt-next-group", &cHardwareCPU::Inst_NumberMTNextGroup, nInstFlag::STALL),
711     tInstLibEntry<tMethod>("kill-group-member", &cHardwareCPU::Inst_KillGroupMember, nInstFlag::STALL),
712 
713     tInstLibEntry<tMethod>("inc-tolerance", &cHardwareCPU::Inst_IncTolerance, nInstFlag::STALL),
714     tInstLibEntry<tMethod>("dec-tolerance", &cHardwareCPU::Inst_DecTolerance, nInstFlag::STALL),
715     tInstLibEntry<tMethod>("get-tolerance", &cHardwareCPU::Inst_GetTolerance, nInstFlag::STALL),
716     tInstLibEntry<tMethod>("get-group-tolerance", &cHardwareCPU::Inst_GetGroupTolerance, nInstFlag::STALL),
717 
718     // Network creation instructions
719     tInstLibEntry<tMethod>("create-link-facing", &cHardwareCPU::Inst_CreateLinkByFacing, nInstFlag::STALL),
720     tInstLibEntry<tMethod>("create-link-xy", &cHardwareCPU::Inst_CreateLinkByXY, nInstFlag::STALL),
721     tInstLibEntry<tMethod>("create-link-index", &cHardwareCPU::Inst_CreateLinkByIndex, nInstFlag::STALL),
722     tInstLibEntry<tMethod>("network-bcast1", &cHardwareCPU::Inst_NetworkBroadcast1, nInstFlag::STALL),
723     tInstLibEntry<tMethod>("network-unicast", &cHardwareCPU::Inst_NetworkUnicast, nInstFlag::STALL),
724     tInstLibEntry<tMethod>("network-rotate", &cHardwareCPU::Inst_NetworkRotate, nInstFlag::STALL),
725     tInstLibEntry<tMethod>("network-select", &cHardwareCPU::Inst_NetworkSelect, nInstFlag::STALL),
726 
727     // Division of labor instructions
728     tInstLibEntry<tMethod>("get-age", &cHardwareCPU::Inst_GetTimeUsed, nInstFlag::STALL),
729     tInstLibEntry<tMethod>("donate-res-to-deme", &cHardwareCPU::Inst_DonateResToDeme, nInstFlag::STALL),
730     tInstLibEntry<tMethod>("point-mut", &cHardwareCPU::Inst_ApplyPointMutations, nInstFlag::STALL),
731     tInstLibEntry<tMethod>("varying-point-mut", &cHardwareCPU::Inst_ApplyVaryingPointMutations, nInstFlag::STALL),
732     tInstLibEntry<tMethod>("point-mut-gs", &cHardwareCPU::Inst_ApplyPointMutationsGroupGS, nInstFlag::STALL),
733     tInstLibEntry<tMethod>("point-mut-rand", &cHardwareCPU::Inst_ApplyPointMutationsGroupRandom, nInstFlag::STALL),
734     tInstLibEntry<tMethod>("join-germline", &cHardwareCPU::Inst_JoinGermline, nInstFlag::STALL),
735     tInstLibEntry<tMethod>("exit-germline", &cHardwareCPU::Inst_ExitGermline, nInstFlag::STALL),
736     tInstLibEntry<tMethod>("repair-on", &cHardwareCPU::Inst_RepairPointMutOn, nInstFlag::STALL),
737     tInstLibEntry<tMethod>("repair-off", &cHardwareCPU::Inst_RepairPointMutOff, nInstFlag::STALL),
738 
739     // Must always be the last instruction in the array
740     tInstLibEntry<tMethod>("NULL", &cHardwareCPU::Inst_Nop, 0, "True no-operation instruction: does nothing"),
741   };
742 
743   const int n_size = sizeof(s_n_array)/sizeof(cNOPEntryCPU);
744 
745   static cString n_names[n_size];
746   static int nop_mods[n_size];
747   for (int i = 0; i < n_size && i < NUM_REGISTERS; i++) {
748     n_names[i] = s_n_array[i].name;
749     nop_mods[i] = s_n_array[i].nop_mod;
750   }
751 
752   const int f_size = sizeof(s_f_array)/sizeof(tInstLibEntry<tMethod>);
753   static tMethod functions[f_size];
754   for (int i = 0; i < f_size; i++) functions[i] = s_f_array[i].GetFunction();
755 
756   const int def = 0;
757   const int null_inst = f_size - 1;
758 
759   return new tInstLib<tMethod>(f_size, s_f_array, n_names, nop_mods, functions, def, null_inst);
760 }
761 
cHardwareCPU(cAvidaContext & ctx,cWorld * world,cOrganism * in_organism,cInstSet * in_inst_set)762 cHardwareCPU::cHardwareCPU(cAvidaContext& ctx, cWorld* world, cOrganism* in_organism, cInstSet* in_inst_set)
763 : cHardwareBase(world, in_organism, in_inst_set)
764 , m_last_cell_data(false, 0)
765 {
766   m_functions = s_inst_slib->GetFunctions();
767 
768   m_spec_die = false;
769   m_epigenetic_state = false;
770 
771   m_thread_slicing_parallel = (m_world->GetConfig().THREAD_SLICING_METHOD.Get() == 1);
772   m_no_cpu_cycle_time = m_world->GetConfig().NO_CPU_CYCLE_TIME.Get();
773 
774   m_promoters_enabled = m_world->GetConfig().PROMOTERS_ENABLED.Get();
775   m_constitutive_regulation = m_world->GetConfig().CONSTITUTIVE_REGULATION.Get();
776 
777   m_slip_read_head = !m_world->GetConfig().SLIP_COPY_MODE.Get();
778 
779   m_memory = in_organism->GetGenome().GetSequence();  // Initialize memory...
780   Reset(ctx);                            // Setup the rest of the hardware...
781   internalReset();
782 }
783 
checkNoMutList(cHeadCPU to)784 bool cHardwareCPU::checkNoMutList(cHeadCPU to)
785 {
786     //Anya's code for head to head experiments
787     //Tests to see if the given cHeadCPU has an instruction that is on the no mutation list, returns false if it is not and true if it is
788     bool in_list = false;
789     char test_inst = to.GetInst().GetSymbol();
790     cString no_mut_list = m_world->GetConfig().NO_MUT_INSTS.Get();
791     for (int i=0; i<(int)strlen(no_mut_list); i++) {
792         if ((char) no_mut_list[i] == test_inst) {
793             in_list = true;
794         }
795     }
796     return in_list;
797 }
798 
799 
internalReset()800 void cHardwareCPU::internalReset()
801 {
802   m_global_stack.Clear();
803 
804   // We want to reset to have a single thread.
805   m_threads.Resize(1);
806 
807   // Reset that single thread.
808   m_threads[0].Reset(this, 0);
809   m_thread_id_chart = 1; // Mark only the first thread as taken...
810   m_cur_thread = 0;
811 
812   // But then reset thread to have any epigenetic information we have saved
813   if (m_epigenetic_state) {
814     for (int i=0; i<NUM_REGISTERS; i++) {
815       m_threads[0].reg[i] = m_epigenetic_saved_reg[i];
816     }
817     m_threads[0].stack = m_epigenetic_saved_stack;
818   }
819 
820   m_mal_active = false;
821   m_executedmatchstrings = false;
822 
823 
824   // Promoter model
825   if (m_world->GetConfig().PROMOTERS_ENABLED.Get()) {
826     // Ideally, this shouldn't be hard-coded
827     cInstruction promoter_inst = m_inst_set->GetInst("promoter");
828 
829     m_promoter_index = -1; // Meaning the last promoter was nothing
830     m_promoter_offset = 0;
831     m_promoters.Resize(0);
832     for (int i=0; i< m_memory.GetSize(); i++)
833     {
834       if (m_memory[i] == promoter_inst)
835       {
836         int code = Numberate(i-1, -1, m_world->GetConfig().PROMOTER_CODE_SIZE.Get());
837         m_promoters.Push( cPromoter(i,code) );
838       }
839     }
840   }
841 
842   m_last_cell_data = std::make_pair(false, 0);
843   // Reset our flash information to 0:
844   m_flash_info.first = 0;
845   m_flash_info.second = 0;
846   // ... as well as our current cycle timer:
847   m_cycle_counter = 0;
848 
849 }
850 
internalResetOnFailedDivide()851 void cHardwareCPU::internalResetOnFailedDivide()
852 {
853   internalReset();
854   m_mal_active = true;
855   m_advance_ip = false;
856 }
857 
858 
859 
operator =(const cLocalThread & in_thread)860 void cHardwareCPU::cLocalThread::operator=(const cLocalThread& in_thread)
861 {
862   m_id = in_thread.m_id;
863   for (int i = 0; i < NUM_REGISTERS; i++) reg[i] = in_thread.reg[i];
864   for (int i = 0; i < NUM_HEADS; i++) heads[i] = in_thread.heads[i];
865   stack = in_thread.stack;
866   m_messageTriggerType = in_thread.m_messageTriggerType;
867 }
868 
Reset(cHardwareBase * in_hardware,int in_id)869 void cHardwareCPU::cLocalThread::Reset(cHardwareBase* in_hardware, int in_id)
870 {
871   m_id = in_id;
872 
873   for (int i = 0; i < NUM_REGISTERS; i++) reg[i] = 0;
874   for (int i = 0; i < NUM_HEADS; i++) heads[i].Reset(in_hardware);
875 
876   stack.Clear();
877   cur_stack = 0;
878   cur_head = nHardware::HEAD_IP;
879   read_label.Clear();
880   next_label.Clear();
881 
882   // Promoter model
883   m_promoter_inst_executed = 0;
884 
885   m_messageTriggerType = -1;
886 
887 }
888 
889 // This function processes the very next command in the genome, and is made
890 // to be as optimized as possible.  This is the heart of avida.
891 
SingleProcess(cAvidaContext & ctx,bool speculative)892 bool cHardwareCPU::SingleProcess(cAvidaContext& ctx, bool speculative)
893 {
894   assert(!speculative || (speculative && !m_thread_slicing_parallel));
895 
896   int last_IP_pos = getIP().GetPosition();
897 
898   // Mark this organism as running...
899   m_organism->SetRunning(true);
900 
901   if (!speculative && m_spec_die) {
902     m_organism->Die(ctx);
903     m_organism->SetRunning(false);
904     return false;
905   }
906 
907   cPhenotype& phenotype = m_organism->GetPhenotype();
908 
909   // First instruction - check whether we should be starting at a promoter, when enabled.
910   if (phenotype.GetCPUCyclesUsed() == 0 && m_promoters_enabled) Inst_Terminate(ctx);
911 
912   // Count the cpu cycles used
913   phenotype.IncCPUCyclesUsed();
914   if (!m_world->GetConfig().NO_CPU_CYCLE_TIME.Get()) phenotype.IncTimeUsed();
915 
916   int num_threads = m_threads.GetSize();
917 
918   // If we have threads turned on and we executed each thread in a single
919   // timestep, adjust the number of instructions executed accordingly.
920   int num_inst_exec = m_thread_slicing_parallel ? num_threads : 1;
921 
922   //  bool isInterruptEnabled(false);
923   //  if (m_world->GetConfig().ACTIVE_MESSAGES_ENABLED.Get() == 1)
924   //    isInterruptEnabled = true;
925 
926   for (int i = 0; i < num_inst_exec; i++) {
927     // Setup the hardware for the next instruction to be executed.
928     int last_thread = m_cur_thread;
929 
930     m_cur_thread++;
931 
932     if (m_cur_thread >= num_threads) m_cur_thread = 0;
933 
934     m_advance_ip = true;
935     cHeadCPU& ip = m_threads[m_cur_thread].heads[nHardware::HEAD_IP];
936     ip.Adjust();
937 
938     // BREAKPOINTS
939 #if 0
940     if (ip.FlagBreakpoint()) {
941       m_organism->DoBreakpoint();
942     }
943 #endif
944 
945     // Print the status of this CPU at each step...
946     if (m_tracer != NULL) m_tracer->TraceHardware(ctx, *this);
947 
948     // Find the instruction to be executed
949     const cInstruction& cur_inst = ip.GetInst();
950 
951     if (speculative && (m_spec_die || m_inst_set->ShouldStall(cur_inst))) {
952       // Speculative instruction reject, flush and return
953       m_cur_thread = last_thread;
954       phenotype.DecCPUCyclesUsed();
955       if (!m_no_cpu_cycle_time) phenotype.IncTimeUsed(-1);
956       m_organism->SetRunning(false);
957       return false;
958     }
959 
960     // Test if costs have been paid and it is okay to execute this now...
961     bool exec = true;
962     if (m_has_any_costs) exec = SingleProcess_PayPreCosts(ctx, cur_inst, m_cur_thread);
963 
964     // Constitutive regulation applied here
965     if (m_constitutive_regulation) Inst_SenseRegulate(ctx);
966 
967     // If there are no active promoters and a certain mode is set, then don't execute any further instructions
968     if (m_promoters_enabled && m_world->GetConfig().NO_ACTIVE_PROMOTER_EFFECT.Get() == 2 && m_promoter_index == -1) exec = false;
969 
970     // Now execute the instruction...
971     if (exec == true) {
972       // NOTE: This call based on the cur_inst must occur prior to instruction
973       //       execution, because this instruction reference may be invalid after
974       //       certain classes of instructions (namely divide instructions) @DMB
975       const int time_cost = m_inst_set->GetAddlTimeCost(cur_inst);
976 
977       // Prob of exec (moved from SingleProcess_PayCosts so that we advance IP after a fail)
978       if (m_inst_set->GetProbFail(cur_inst) > 0.0) {
979         exec = !( ctx.GetRandom().P(m_inst_set->GetProbFail(cur_inst)) );
980       }
981 
982       // Flag instruction as executed even if it failed (moved from SingleProcess_ExecuteInst)
983       // this allows division conditions to be met even if most instruction executions failed. @JEB
984 
985       // Mark the instruction as executed
986       getIP().SetFlagExecuted();
987 
988       // Add to the promoter inst executed count before executing the inst (in case it is a terminator)
989       if (m_promoters_enabled) m_threads[m_cur_thread].IncPromoterInstExecuted();
990 
991       if (exec == true) {
992         if (SingleProcess_ExecuteInst(ctx, cur_inst)) {
993           SingleProcess_PayPostResCosts(ctx, cur_inst);
994           SingleProcess_SetPostCPUCosts(ctx, cur_inst, m_cur_thread);
995         }
996       }
997 
998       // Check if the instruction just executed caused premature death, break out of execution if so
999       if (phenotype.GetToDelete()) break;
1000 
1001       // Some instruction (such as jump) may turn m_advance_ip off.  Usually
1002       // we now want to move to the next instruction in the memory.
1003       if (m_advance_ip == true) ip.Advance();
1004 
1005       // Pay the time cost of the instruction now
1006       phenotype.IncTimeUsed(time_cost);
1007 
1008       // In the promoter model, we may force termination after a certain number of inst have been executed
1009       if (m_promoters_enabled) {
1010         const double processivity = m_world->GetConfig().PROMOTER_PROCESSIVITY.Get();
1011         if (ctx.GetRandom().P(1 - processivity)) Inst_Terminate(ctx);
1012         if (m_world->GetConfig().PROMOTER_INST_MAX.Get() && (m_threads[m_cur_thread].GetPromoterInstExecuted() >= m_world->GetConfig().PROMOTER_INST_MAX.Get()))
1013           Inst_Terminate(ctx);
1014       }
1015 
1016       // check for difference in thread count caused by KillThread or ForkThread
1017       if (num_threads == m_threads.GetSize()+1){
1018         --num_threads;
1019         --num_inst_exec;
1020       } else if (num_threads > m_threads.GetSize() && m_threads.GetSize() == 1) {
1021         // divide probably occured, I think divide insts. are the only ones that can reduce the thread count by more than one.
1022         num_threads = 1;
1023         num_inst_exec=0;
1024       } else if (num_threads > m_threads.GetSize()) {
1025         cerr<<cur_inst.GetOp()<<" "<<cur_inst.GetSymbol()<<" "<< num_threads << " " << m_threads.GetSize() <<endl;
1026         m_organism->Fault(FAULT_LOC_DEFAULT, FAULT_TYPE_ERROR);
1027         cerr<<"Error in thread handling\n";
1028         exit(-1);
1029       }
1030     } // if exec
1031 
1032   } // Previous was executed once for each thread...
1033 
1034   // Kill creatures who have reached their max num of instructions executed
1035   const int max_executed = m_organism->GetMaxExecuted();
1036   if ((max_executed > 0 && phenotype.GetTimeUsed() >= max_executed) || phenotype.GetToDie() == true) {
1037     if (speculative) m_spec_die = true;
1038     else m_organism->Die(ctx);
1039   }
1040   if (!speculative && phenotype.GetToDelete()) m_spec_die = true;
1041 
1042   // Note: if organism just died, this will NOT let it repro.
1043   CheckImplicitRepro(ctx, last_IP_pos > m_threads[m_cur_thread].heads[nHardware::HEAD_IP].GetPosition());
1044 
1045   m_organism->SetRunning(false);
1046 
1047   return !m_spec_die;
1048 }
1049 
1050 // This method will handle the actual execution of an instruction
1051 // within a single process, once that function has been finalized.
SingleProcess_ExecuteInst(cAvidaContext & ctx,const cInstruction & cur_inst)1052 bool cHardwareCPU::SingleProcess_ExecuteInst(cAvidaContext& ctx, const cInstruction& cur_inst)
1053 {
1054   // Copy Instruction locally to handle stochastic effects
1055   cInstruction actual_inst = cur_inst;
1056 
1057 #ifdef EXECUTION_ERRORS
1058   // If there is an execution error, execute a random instruction.
1059   if (m_organism->TestExeErr()) actual_inst = m_inst_set->GetRandomInst(ctx);
1060 #endif /* EXECUTION_ERRORS */
1061 
1062   // Get a pointer to the corresponding method...
1063   int inst_idx = m_inst_set->GetLibFunctionIndex(actual_inst);
1064 
1065   // instruction execution count incremented
1066   m_organism->GetPhenotype().IncCurInstCount(actual_inst.GetOp());
1067 
1068   // And execute it.
1069   const bool exec_success = (this->*(m_functions[inst_idx]))(ctx);
1070 
1071   // NOTE: Organism may be dead now if instruction executed killed it (such as some divides, "die", or "kazi")
1072 
1073   // Add in a cycle cost for switching which task is performed
1074   if (m_world->GetConfig().TASK_SWITCH_PENALTY_TYPE.Get()) {
1075     if (m_organism->GetPhenotype().GetNumNewUniqueReactions()) {
1076       int cost = m_organism->GetPhenotype().GetNumNewUniqueReactions() * m_world->GetConfig().TASK_SWITCH_PENALTY.Get();
1077       IncrementTaskSwitchingCost(cost);
1078 
1079       m_organism->GetPhenotype().ResetNumNewUniqueReactions();
1080     }
1081   }
1082 
1083   // Decrement if the instruction was not executed successfully.
1084   if (exec_success == false) {
1085     m_organism->GetPhenotype().DecCurInstCount(actual_inst.GetOp());
1086   }
1087 
1088   return exec_success;
1089 }
1090 
1091 
ProcessBonusInst(cAvidaContext & ctx,const cInstruction & inst)1092 void cHardwareCPU::ProcessBonusInst(cAvidaContext& ctx, const cInstruction& inst)
1093 {
1094   // Mark this organism as running...
1095   bool prev_run_state = m_organism->IsRunning();
1096   m_organism->SetRunning(true);
1097 
1098   if (m_tracer != NULL) m_tracer->TraceHardware(ctx, *this, true);
1099 
1100   SingleProcess_ExecuteInst(ctx, inst);
1101 
1102   m_organism->SetRunning(prev_run_state);
1103 }
1104 
1105 
PrintStatus(ostream & fp)1106 void cHardwareCPU::PrintStatus(ostream& fp)
1107 {
1108   fp << m_organism->GetPhenotype().GetCPUCyclesUsed() << " ";
1109   fp << "IP:" << getIP().GetPosition() << "    ";
1110 
1111   for (int i = 0; i < NUM_REGISTERS; i++) {
1112     fp << static_cast<char>('A' + i) << "X:" << GetRegister(i) << " ";
1113     fp << setbase(16) << "[0x" << GetRegister(i) << "]  " << setbase(10);
1114   }
1115 
1116   if (m_organism->IsInterrupted()) {
1117     fp << "  Interrupted";
1118   }
1119 
1120   // Add some extra information if additional time costs are used for instructions,
1121   // leave this out if there are no differences to keep it cleaner
1122   if (m_organism->GetPhenotype().GetTimeUsed() != m_organism->GetPhenotype().GetCPUCyclesUsed()) {
1123     fp << "  EnergyUsed:" << m_organism->GetPhenotype().GetTimeUsed(); // this is not energy that is used by the energy model
1124   }
1125   fp << endl;
1126 
1127   fp << "  R-Head:" << getHead(nHardware::HEAD_READ).GetPosition() << " "
1128   << "W-Head:" << getHead(nHardware::HEAD_WRITE).GetPosition()  << " "
1129   << "F-Head:" << getHead(nHardware::HEAD_FLOW).GetPosition()   << "  "
1130   << "RL:" << GetReadLabel().AsString() << "   "
1131   << endl;
1132 
1133   int number_of_stacks = GetNumStacks();
1134   for (int stack_id = 0; stack_id < number_of_stacks; stack_id++) {
1135     fp << ((m_threads[m_cur_thread].cur_stack == stack_id) ? '*' : ' ') << " Stack " << stack_id << ":" << setbase(16) << setfill('0');
1136     for (int i = 0; i < nHardware::STACK_SIZE; i++) fp << " Ox" << setw(8) << GetStack(i, stack_id, 0);
1137     fp << setfill(' ') << setbase(10) << endl;
1138   }
1139 
1140   fp << "  Mem (" << m_memory.GetSize() << "):"
1141   << "  " << m_memory.AsString()
1142   << endl;
1143 
1144   if (m_ext_mem.GetSize()) {
1145     fp << "  Ext Mem: " << m_ext_mem[0];
1146     for (int i = 1; i < m_ext_mem.GetSize(); i++) fp << ", " << m_ext_mem[i];
1147     fp << endl;
1148   }
1149 
1150   if (m_world->GetConfig().PROMOTERS_ENABLED.Get())
1151   {
1152     fp << "  Promoters: index=" << m_promoter_index << " offset=" << m_promoter_offset;
1153     fp << " exe_inst=" << m_threads[m_cur_thread].GetPromoterInstExecuted();
1154     for (int i=0; i<m_promoters.GetSize(); i++) {
1155       fp << setfill(' ') << setbase(10) << " " << m_promoters[i].m_pos << ":";
1156       fp << "Ox" << setbase(16) << setfill('0') << setw(8) << (m_promoters[i].GetRegulatedBitCode()) << " ";
1157     }
1158     fp << setfill(' ') << setbase(10) << endl;
1159   }
1160   fp.flush();
1161 }
1162 
1163 /////////////////////////////////////////////////////////////////////////
1164 // Method: cHardwareCPU::FindLabel(direction)
1165 //
1166 // Search in 'direction' (+ or - 1) from the instruction pointer for the
1167 // compliment of the label in 'next_label' and return a pointer to the
1168 // results.  If direction is 0, search from the beginning of the genome.
1169 //
1170 /////////////////////////////////////////////////////////////////////////
1171 
FindLabel(int direction)1172 cHeadCPU cHardwareCPU::FindLabel(int direction)
1173 {
1174   cHeadCPU & inst_ptr = getIP();
1175 
1176   // Start up a search head at the position of the instruction pointer.
1177   cHeadCPU search_head(inst_ptr);
1178   cCodeLabel & search_label = GetLabel();
1179 
1180   // Make sure the label is of size > 0.
1181 
1182   if (search_label.GetSize() == 0) {
1183     return inst_ptr;
1184   }
1185 
1186   // Call special functions depending on if jump is forwards or backwards.
1187   int found_pos = 0;
1188   if ( direction < 0 ) {
1189     found_pos = FindLabel_Backward(search_label, m_memory, inst_ptr.GetPosition() - search_label.GetSize());
1190   }
1191 
1192   // Jump forward.
1193   else if (direction > 0) {
1194     found_pos = FindLabel_Forward(search_label, m_memory, inst_ptr.GetPosition());
1195   }
1196 
1197   // Jump forward from the very beginning.
1198   else {
1199     found_pos = FindLabel_Forward(search_label, m_memory, 0);
1200   }
1201 
1202   // Return the last line of the found label, if it was found.
1203   if (found_pos >= 0) search_head.Set(found_pos - 1);
1204 
1205   // Return the found position (still at start point if not found).
1206   return search_head;
1207 }
1208 
1209 
1210 // Search forwards for search_label from _after_ position pos in the
1211 // memory.  Return the first line _after_ the the found label.  It is okay
1212 // to find search label's match inside another label.
1213 
FindLabel_Forward(const cCodeLabel & search_label,const Sequence & search_genome,int pos)1214 int cHardwareCPU::FindLabel_Forward(const cCodeLabel & search_label,
1215                                     const Sequence & search_genome, int pos)
1216 {
1217   assert (pos < search_genome.GetSize() && pos >= 0);
1218 
1219   int search_start = pos;
1220   int label_size = search_label.GetSize();
1221   bool found_label = false;
1222 
1223   // Move off the template we are on.
1224   pos += label_size;
1225 
1226   // Search until we find the complement or exit the memory.
1227   while (pos < search_genome.GetSize()) {
1228 
1229     // If we are within a label, rewind to the beginning of it and see if
1230     // it has the proper sub-label that we're looking for.
1231 
1232     if (m_inst_set->IsNop(search_genome[pos])) {
1233       // Find the start and end of the label we're in the middle of.
1234 
1235       int start_pos = pos;
1236       int end_pos = pos + 1;
1237       while (start_pos > search_start &&
1238              m_inst_set->IsNop( search_genome[start_pos - 1] )) {
1239         start_pos--;
1240       }
1241       while (end_pos < search_genome.GetSize() &&
1242              m_inst_set->IsNop( search_genome[end_pos] )) {
1243         end_pos++;
1244       }
1245       int test_size = end_pos - start_pos;
1246 
1247       // See if this label has the proper sub-label within it.
1248       int max_offset = test_size - label_size + 1;
1249       int offset = start_pos;
1250       for (offset = start_pos; offset < start_pos + max_offset; offset++) {
1251 
1252         // Test the number of matches for this offset.
1253         int matches;
1254         for (matches = 0; matches < label_size; matches++) {
1255           if (search_label[matches] !=
1256               m_inst_set->GetNopMod( search_genome[offset + matches] )) {
1257             break;
1258           }
1259         }
1260 
1261         // If we have found it, break out of this loop!
1262         if (matches == label_size) {
1263           found_label = true;
1264           break;
1265         }
1266       }
1267 
1268       // If we've found the complement label, set the position to the end of
1269       // the label we found it in, and break out.
1270 
1271       if (found_label == true) {
1272         // pos = end_pos;
1273         pos = label_size + offset;
1274         break;
1275       }
1276 
1277       // We haven't found it; jump pos to just after the current label being
1278       // checked.
1279       pos = end_pos;
1280     }
1281 
1282     // Jump up a block to the next possible point to find a label,
1283     pos += label_size;
1284   }
1285 
1286   // If the label was not found return a -1.
1287   if (found_label == false) pos = -1;
1288 
1289   return pos;
1290 }
1291 
1292 // Search backwards for search_label from _before_ position pos in the
1293 // memory.  Return the first line _after_ the the found label.  It is okay
1294 // to find search label's match inside another label.
1295 
FindLabel_Backward(const cCodeLabel & search_label,const Sequence & search_genome,int pos)1296 int cHardwareCPU::FindLabel_Backward(const cCodeLabel & search_label,
1297                                      const Sequence & search_genome, int pos)
1298 {
1299   assert (pos < search_genome.GetSize());
1300 
1301   int search_start = pos;
1302   int label_size = search_label.GetSize();
1303   bool found_label = false;
1304 
1305   // Move off the template we are on.
1306   pos -= label_size;
1307 
1308   // Search until we find the complement or exit the memory.
1309   while (pos >= 0) {
1310     // If we are within a label, rewind to the beginning of it and see if
1311     // it has the proper sub-label that we're looking for.
1312 
1313     if (m_inst_set->IsNop( search_genome[pos] )) {
1314       // Find the start and end of the label we're in the middle of.
1315 
1316       int start_pos = pos;
1317       int end_pos = pos + 1;
1318       while (start_pos > 0 && m_inst_set->IsNop(search_genome[start_pos - 1])) {
1319         start_pos--;
1320       }
1321       while (end_pos < search_start &&
1322              m_inst_set->IsNop(search_genome[end_pos])) {
1323         end_pos++;
1324       }
1325       int test_size = end_pos - start_pos;
1326 
1327       // See if this label has the proper sub-label within it.
1328       int max_offset = test_size - label_size + 1;
1329       for (int offset = start_pos; offset < start_pos + max_offset; offset++) {
1330 
1331         // Test the number of matches for this offset.
1332         int matches;
1333         for (matches = 0; matches < label_size; matches++) {
1334           if (search_label[matches] !=
1335               m_inst_set->GetNopMod(search_genome[offset + matches])) {
1336             break;
1337           }
1338         }
1339 
1340         // If we have found it, break out of this loop!
1341         if (matches == label_size) {
1342           found_label = true;
1343           break;
1344         }
1345       }
1346 
1347       // If we've found the complement label, set the position to the end of
1348       // the label we found it in, and break out.
1349 
1350       if (found_label == true) {
1351         pos = end_pos;
1352         break;
1353       }
1354 
1355       // We haven't found it; jump pos to just before the current label
1356       // being checked.
1357       pos = start_pos - 1;
1358     }
1359 
1360     // Jump up a block to the next possible point to find a label,
1361     pos -= label_size;
1362   }
1363 
1364   // If the label was not found return a -1.
1365   if (found_label == false) pos = -1;
1366 
1367   return pos;
1368 }
1369 
1370 // Search for 'in_label' anywhere in the hardware.
FindLabel(const cCodeLabel & in_label,int direction)1371 cHeadCPU cHardwareCPU::FindLabel(const cCodeLabel & in_label, int direction)
1372 {
1373   assert (in_label.GetSize() > 0);
1374 
1375   // IDEALY:
1376   // Keep making jumps (in the proper direction) equal to the label
1377   // length.  If we are inside of a label, check its size, and see if
1378   // any of the sub-labels match properly.
1379   // FOR NOW:
1380   // Get something which works, no matter how inefficient!!!
1381 
1382   cHeadCPU temp_head(this);
1383 
1384   while (temp_head.InMemory()) {
1385     // IDEALY: Analyze the label we are in; see if the one we are looking
1386     // for could be a sub-label of it.  Skip past it if not.
1387 
1388     int i;
1389     for (i = 0; i < in_label.GetSize(); i++) {
1390       if (!m_inst_set->IsNop(temp_head.GetInst()) ||
1391           in_label[i] != m_inst_set->GetNopMod(temp_head.GetInst())) {
1392         break;
1393       }
1394     }
1395     if (i == GetLabel().GetSize()) {
1396       temp_head.AbsJump(i - 1);
1397       return temp_head;
1398     }
1399 
1400     temp_head.AbsJump(direction);     // IDEALY: MAKE LARGER JUMPS
1401   }
1402 
1403   temp_head.AbsSet(-1);
1404   return temp_head;
1405 }
1406 
1407 
1408 
ReadInst(const int in_inst)1409 void cHardwareCPU::ReadInst(const int in_inst)
1410 {
1411   if (m_inst_set->IsNop( cInstruction(in_inst) )) {
1412     GetReadLabel().AddNop(in_inst);
1413   } else {
1414     GetReadLabel().Clear();
1415   }
1416 }
1417 
1418 
AdjustHeads()1419 void cHardwareCPU::AdjustHeads()
1420 {
1421   for (int i = 0; i < m_threads.GetSize(); i++) {
1422     for (int j = 0; j < NUM_HEADS; j++) {
1423       m_threads[i].heads[j].Adjust();
1424     }
1425   }
1426 }
1427 
1428 
1429 
1430 // This function looks at the current position in the info of a creature,
1431 // and sets the next_label to be the sequence of nops which follows.  The
1432 // instruction pointer is left on the last line of the label found.
1433 
ReadLabel(int max_size)1434 void cHardwareCPU::ReadLabel(int max_size)
1435 {
1436   int count = 0;
1437   cHeadCPU * inst_ptr = &( getIP() );
1438 
1439   GetLabel().Clear();
1440 
1441   while (m_inst_set->IsNop(inst_ptr->GetNextInst()) &&
1442          (count < max_size)) {
1443     count++;
1444     inst_ptr->Advance();
1445     GetLabel().AddNop(m_inst_set->GetNopMod(inst_ptr->GetInst()));
1446 
1447     // If this is the first line of the template, mark it executed.
1448     if (GetLabel().GetSize() <=	m_world->GetConfig().MAX_LABEL_EXE_SIZE.Get()) {
1449       inst_ptr->SetFlagExecuted();
1450     }
1451   }
1452 }
1453 
1454 
ForkThread()1455 bool cHardwareCPU::ForkThread()
1456 {
1457   const int num_threads = m_threads.GetSize();
1458   if (num_threads == m_world->GetConfig().MAX_CPU_THREADS.Get()) return false;
1459 
1460   // Make room for the new thread.
1461   m_threads.Resize(num_threads + 1);
1462 
1463   // Initialize the new thread to the same values as the current one.
1464   m_threads[num_threads] = m_threads[m_cur_thread];
1465 
1466   // Find the first free bit in m_thread_id_chart to determine the new
1467   // thread id.
1468   int new_id = 0;
1469   while ( (m_thread_id_chart >> new_id) & 1) new_id++;
1470   m_threads[num_threads].SetID(new_id);
1471   m_thread_id_chart |= (1 << new_id);
1472 
1473   return true;
1474 }
1475 
InterruptThread(int interruptType)1476 bool cHardwareCPU::InterruptThread(int interruptType) {
1477   //Will interrupt be successful? i.e. is head instuction present?
1478   cString handlerHeadInstructionString;
1479   int interruptMsgType(-1);
1480 
1481   switch (interruptType) {
1482     case MSG_INTERRUPT:
1483       interruptMsgType = GetOrganism()->PeekAtNextMessageType();
1484       handlerHeadInstructionString.Set("msg-handler-type%d", interruptMsgType);
1485       break;
1486     case MOVE_INTERRUPT:
1487       handlerHeadInstructionString.Set("moved-handler");
1488       break;
1489     default:
1490 			cerr <<  "Unknown intrerrupt type " << interruptType << "  Exitting.\n\n";
1491       exit(-1);
1492       break;
1493   }
1494 
1495   const cInstruction label_inst = GetInstSet().GetInst(handlerHeadInstructionString);
1496 
1497   cHeadCPU search_head(IP());
1498   int start_pos = search_head.GetPosition();
1499   search_head++;
1500 
1501   while (start_pos != search_head.GetPosition()) {
1502     if (search_head.GetInst() == label_inst) {  // found handlerHeadInstructionString
1503       search_head++;  // one instruction past instruction
1504       break;
1505     }
1506     search_head++;
1507   }
1508 
1509   if (start_pos == search_head.GetPosition()) {
1510     return false; // no instruction denoting start of interrupt handler
1511   }
1512 
1513   if (ForkThread()) {
1514     // interrupt stuff
1515     const int num_threads = m_threads.GetSize()-1;
1516     m_threads[num_threads].setMessageTriggerType(interruptMsgType);
1517 
1518     int old_thread = m_cur_thread;
1519     m_cur_thread = num_threads;
1520 
1521     // move all heads to one past beginning of interrupt
1522     for (int i = 0; i < NUM_HEADS; i++) {
1523       GetHead(i).Set(search_head.GetPosition());
1524     }
1525 
1526     switch (interruptType) {
1527       case MSG_INTERRUPT:
1528         IP().Retreat();
1529         Inst_RetrieveMessage(m_world->GetDefaultContext());
1530         IP().Advance();
1531         break;
1532       case MOVE_INTERRUPT:
1533         // do nothing extra
1534         break;
1535     }
1536     m_cur_thread = old_thread;
1537     return true;
1538   }
1539   return false;
1540 }
1541 
KillThread()1542 bool cHardwareCPU::KillThread()
1543 {
1544   // Make sure that there is always at least one thread...
1545   if (m_threads.GetSize() == 1) return false;
1546 
1547   // Note the current thread and set the current back one.
1548   const int kill_thread = m_cur_thread;
1549   ThreadPrev();
1550 
1551   // Turn off this bit in the m_thread_id_chart...
1552   m_thread_id_chart ^= 1 << m_threads[kill_thread].GetID();
1553 
1554   // Copy the last thread into the kill position
1555   const int last_thread = m_threads.GetSize() - 1;
1556   if (last_thread != kill_thread) {
1557     m_threads[kill_thread] = m_threads[last_thread];
1558   }
1559 
1560   // Kill the thread!
1561   m_threads.Resize(m_threads.GetSize() - 1);
1562 
1563   if (m_cur_thread > kill_thread) m_cur_thread--;
1564 
1565   return true;
1566 }
1567 
1568 ////////////////////////////
1569 //  Instruction Helpers...
1570 ////////////////////////////
1571 
FindModifiedRegister(int default_register)1572 inline int cHardwareCPU::FindModifiedRegister(int default_register)
1573 {
1574   assert(default_register < NUM_REGISTERS);  // Reg ID too high.
1575 
1576   if (m_inst_set->IsNop(getIP().GetNextInst())) {
1577     getIP().Advance();
1578     default_register = m_inst_set->GetNopMod(getIP().GetInst());
1579     getIP().SetFlagExecuted();
1580   }
1581   return default_register;
1582 }
1583 
FindModifiedNextRegister(int default_register)1584 inline int cHardwareCPU::FindModifiedNextRegister(int default_register)
1585 {
1586   assert(default_register < NUM_REGISTERS);  // Reg ID too high.
1587 
1588   if (m_inst_set->IsNop(getIP().GetNextInst())) {
1589     getIP().Advance();
1590     default_register = m_inst_set->GetNopMod(getIP().GetInst());
1591     getIP().SetFlagExecuted();
1592   } else {
1593     default_register = (default_register + 1) % NUM_REGISTERS;
1594   }
1595   return default_register;
1596 }
1597 
FindModifiedPreviousRegister(int default_register)1598 inline int cHardwareCPU::FindModifiedPreviousRegister(int default_register)
1599 {
1600   assert(default_register < NUM_REGISTERS);  // Reg ID too high.
1601 
1602   if (m_inst_set->IsNop(getIP().GetNextInst())) {
1603     getIP().Advance();
1604     default_register = m_inst_set->GetNopMod(getIP().GetInst());
1605     getIP().SetFlagExecuted();
1606   } else {
1607     default_register = (default_register + NUM_REGISTERS - 1) % NUM_REGISTERS;
1608   }
1609   return default_register;
1610 }
1611 
1612 
FindModifiedHead(int default_head)1613 inline int cHardwareCPU::FindModifiedHead(int default_head)
1614 {
1615   assert(default_head < NUM_HEADS); // Head ID too high.
1616 
1617   if (m_inst_set->IsNop(getIP().GetNextInst())) {
1618     getIP().Advance();
1619     default_head = m_inst_set->GetNopMod(getIP().GetInst());
1620     getIP().SetFlagExecuted();
1621   }
1622   return default_head;
1623 }
1624 
1625 
FindNextRegister(int base_reg)1626 inline int cHardwareCPU::FindNextRegister(int base_reg)
1627 {
1628   return (base_reg + 1) % NUM_REGISTERS;
1629 }
1630 
1631 
Allocate_Necro(const int new_size)1632 bool cHardwareCPU::Allocate_Necro(const int new_size)
1633 {
1634   m_memory.ResizeOld(new_size);
1635   return true;
1636 }
1637 
Allocate_Random(cAvidaContext & ctx,const int old_size,const int new_size)1638 bool cHardwareCPU::Allocate_Random(cAvidaContext& ctx, const int old_size, const int new_size)
1639 {
1640   m_memory.Resize(new_size);
1641 
1642   for (int i = old_size; i < new_size; i++) {
1643     m_memory[i] = m_inst_set->GetRandomInst(ctx);
1644   }
1645   return true;
1646 }
1647 
Allocate_Default(const int new_size)1648 bool cHardwareCPU::Allocate_Default(const int new_size)
1649 {
1650   m_memory.Resize(new_size);
1651 
1652   // New space already defaults to default instruction...
1653 
1654   return true;
1655 }
1656 
Allocate_Main(cAvidaContext & ctx,const int allocated_size)1657 bool cHardwareCPU::Allocate_Main(cAvidaContext& ctx, const int allocated_size)
1658 {
1659   // must do divide before second allocate & must allocate positive amount...
1660   if (m_world->GetConfig().REQUIRE_ALLOCATE.Get() && m_mal_active == true) {
1661     m_organism->Fault(FAULT_LOC_ALLOC, FAULT_TYPE_ERROR, "Allocate already active");
1662     return false;
1663   }
1664   if (allocated_size < 1) {
1665     m_organism->Fault(FAULT_LOC_ALLOC, FAULT_TYPE_ERROR,
1666                       cStringUtil::Stringf("Allocate of %d too small", allocated_size));
1667     return false;
1668   }
1669 
1670   const int old_size = m_memory.GetSize();
1671   const int new_size = old_size + allocated_size;
1672 
1673   // Make sure that the new size is in range.
1674   if (new_size > MAX_GENOME_LENGTH  ||  new_size < MIN_GENOME_LENGTH) {
1675     m_organism->Fault(FAULT_LOC_ALLOC, FAULT_TYPE_ERROR,
1676                       cStringUtil::Stringf("Invalid post-allocate size (%d)",
1677                                            new_size));
1678     return false;
1679   }
1680 
1681   const int max_alloc_size = (int) (old_size * m_world->GetConfig().OFFSPRING_SIZE_RANGE.Get());
1682   if (allocated_size > max_alloc_size) {
1683     m_organism->Fault(FAULT_LOC_ALLOC, FAULT_TYPE_ERROR,
1684                       cStringUtil::Stringf("Allocate too large (%d > %d)",
1685                                            allocated_size, max_alloc_size));
1686     return false;
1687   }
1688 
1689   const int max_old_size =
1690   (int) (allocated_size * m_world->GetConfig().OFFSPRING_SIZE_RANGE.Get());
1691   if (old_size > max_old_size) {
1692     m_organism->Fault(FAULT_LOC_ALLOC, FAULT_TYPE_ERROR,
1693                       cStringUtil::Stringf("Allocate too small (%d > %d)",
1694                                            old_size, max_old_size));
1695     return false;
1696   }
1697 
1698   switch (m_world->GetConfig().ALLOC_METHOD.Get()) {
1699     case ALLOC_METHOD_NECRO:
1700       // Only break if this succeeds -- otherwise just do random.
1701       if (Allocate_Necro(new_size) == true) break;
1702     case ALLOC_METHOD_RANDOM:
1703       Allocate_Random(ctx, old_size, new_size);
1704       break;
1705     case ALLOC_METHOD_DEFAULT:
1706       Allocate_Default(new_size);
1707       break;
1708   }
1709 
1710   m_mal_active = true;
1711 
1712   return true;
1713 }
1714 
calcCopiedSize(const int parent_size,const int child_size)1715 int cHardwareCPU::calcCopiedSize(const int parent_size, const int child_size)
1716 {
1717   int copied_size = 0;
1718   for (int i = parent_size; i < parent_size + child_size; i++) {
1719     if (m_memory.FlagCopied(i)) copied_size++;
1720   }
1721   return copied_size;
1722 }
1723 
1724 
Divide_Main(cAvidaContext & ctx,const int div_point,const int extra_lines,double mut_multiplier)1725 bool cHardwareCPU::Divide_Main(cAvidaContext& ctx, const int div_point,
1726                                const int extra_lines, double mut_multiplier)
1727 {
1728   const int child_size = m_memory.GetSize() - div_point - extra_lines;
1729 
1730   // Make sure this divide will produce a viable offspring.
1731   const bool viable = Divide_CheckViable(ctx, div_point, child_size);
1732   if (viable == false) return false;
1733 
1734   // Since the divide will now succeed, set up the information to be sent
1735   // to the new organism
1736   Sequence& child_genome = m_organism->OffspringGenome().GetSequence();
1737   child_genome = m_memory.Crop(div_point, div_point + child_size);
1738   m_organism->OffspringGenome().SetHardwareType(GetType());
1739   m_organism->OffspringGenome().SetInstSet(m_inst_set->GetInstSetName());
1740 
1741   // Make sure it is an exact copy at this point (before divide mutations) if required
1742   if (m_world->GetConfig().REQUIRE_EXACT_COPY.Get() && (m_organism->GetGenome().GetSequence() != child_genome) ) {
1743     return false;
1744   }
1745 
1746   // Cut off everything in this memory past the divide point.
1747   m_memory.Resize(div_point);
1748 
1749   // Handle Divide Mutations...
1750   Divide_DoMutations(ctx, mut_multiplier);
1751 
1752   // Many tests will require us to run the offspring through a test CPU;
1753   // this is, for example, to see if mutations need to be reverted or if
1754   // lineages need to be updated.
1755   Divide_TestFitnessMeasures1(ctx);
1756 
1757   if (m_world->GetConfig().DIVIDE_METHOD.Get() != DIVIDE_METHOD_OFFSPRING) {
1758     // reset first time instruction costs
1759     for (int i = 0; i < m_inst_ft_cost.GetSize(); i++) {
1760       m_inst_ft_cost[i] = m_inst_set->GetFTCost(cInstruction(i));
1761     }
1762   }
1763 
1764   m_mal_active = false;
1765   if (m_world->GetConfig().DIVIDE_METHOD.Get() == DIVIDE_METHOD_SPLIT) {
1766     m_advance_ip = false;
1767   }
1768 
1769   // Activate the child
1770   bool parent_alive = m_organism->ActivateDivide(ctx);
1771 
1772   // Do more work if the parent lives through the birth of the offspring
1773   if (parent_alive) {
1774 
1775     if ( (m_world->GetConfig().EPIGENETIC_METHOD.Get() == EPIGENETIC_METHOD_PARENT)
1776         || (m_world->GetConfig().EPIGENETIC_METHOD.Get() == EPIGENETIC_METHOD_BOTH) ) {
1777       InheritState(*this);
1778     }
1779 
1780     if (m_world->GetConfig().DIVIDE_METHOD.Get() == DIVIDE_METHOD_SPLIT) Reset(ctx);
1781   }
1782 
1783   return true;
1784 }
1785 
1786 /*
1787  Almost the same as Divide_Main, but resamples reverted offspring.
1788 
1789  RESAMPLING ONLY WORKS CORRECTLY WHEN ALL MUTIONS OCCUR ON DIVIDE!!
1790 
1791  AWC - 06/29/06
1792  */
Divide_MainRS(cAvidaContext & ctx,const int div_point,const int extra_lines,double mut_multiplier)1793 bool cHardwareCPU::Divide_MainRS(cAvidaContext& ctx, const int div_point,
1794                                  const int extra_lines, double mut_multiplier)
1795 {
1796 
1797   //cStats stats = m_world->GetStats();
1798   const int child_size = m_memory.GetSize() - div_point - extra_lines;
1799 
1800   // Make sure this divide will produce a viable offspring.
1801   const bool viable = Divide_CheckViable(ctx, div_point, child_size);
1802   if (viable == false) return false;
1803 
1804   // Since the divide will now succeed, set up the information to be sent
1805   // to the new organism
1806   Sequence& child_genome = m_organism->OffspringGenome().GetSequence();
1807   child_genome = m_memory.Crop(div_point, div_point + child_size);
1808   m_organism->OffspringGenome().SetHardwareType(GetType());
1809   m_organism->OffspringGenome().SetInstSet(m_inst_set->GetInstSetName());
1810 
1811   // Cut off everything in this memory past the divide point.
1812   m_memory.Resize(div_point);
1813 
1814   unsigned
1815   totalMutations = 0,
1816   mutations = 0;
1817   //RScount = 0;
1818 
1819 
1820   bool
1821   fitTest = false;
1822 
1823   // Handle Divide Mutations...
1824   /*
1825    Do mutations until one of these conditions are satisified:
1826    we have resampled X times
1827    we have an offspring with the same number of muations as the first offspring
1828    that is not reverted
1829    the parent is steralized (usually means an implicit mutation)
1830    */
1831   for (unsigned i = 0; i <= 100; i++) {
1832     if (i == 0) {
1833       mutations = totalMutations = Divide_DoMutations(ctx, mut_multiplier);
1834     }
1835     else{
1836       mutations = Divide_DoMutations(ctx, mut_multiplier);
1837       m_world->GetStats().IncResamplings();
1838     }
1839 
1840     fitTest = Divide_TestFitnessMeasures1(ctx);
1841 
1842     if (!fitTest && mutations >= totalMutations) break;
1843 
1844   }
1845   // think about making this mutations == totalMuations - though this may be too hard...
1846   /*
1847    if (RScount > 2)
1848    cerr << "Resampled " << RScount << endl;
1849    */
1850   //org could not be resampled beneath the hard cap -- it is then steraalized
1851   if (fitTest/*RScount == 11*/) {
1852     m_organism->GetPhenotype().ChildFertile() = false;
1853     m_world->GetStats().IncFailedResamplings();
1854   }
1855 
1856   if (m_world->GetConfig().DIVIDE_METHOD.Get() != DIVIDE_METHOD_OFFSPRING) {
1857 
1858     // reset first time instruction costs
1859     for (int i = 0; i < m_inst_ft_cost.GetSize(); i++) {
1860       m_inst_ft_cost[i] = m_inst_set->GetFTCost(cInstruction(i));
1861     }
1862   }
1863 
1864   m_mal_active = false;
1865   if (m_world->GetConfig().DIVIDE_METHOD.Get() == DIVIDE_METHOD_SPLIT) {
1866     m_advance_ip = false;
1867   }
1868 
1869   // Activate the child, and do more work if the parent lives through the
1870   // birth.
1871   bool parent_alive = m_organism->ActivateDivide(ctx);
1872   if (parent_alive) {
1873     if (m_world->GetConfig().DIVIDE_METHOD.Get() == DIVIDE_METHOD_SPLIT) Reset(ctx);
1874   }
1875 
1876   return true;
1877 }
1878 
1879 /*
1880  Almost the same as Divide_Main, but only allows for one mutation
1881  on divde and resamples reverted offspring.
1882 
1883  RESAMPLING ONLY WORKS CORRECTLY WHEN ALL MUTIONS OCCUR ON DIVIDE!!
1884 
1885  AWC - 07/28/06
1886  */
Divide_Main1RS(cAvidaContext & ctx,const int div_point,const int extra_lines,double mut_multiplier)1887 bool cHardwareCPU::Divide_Main1RS(cAvidaContext& ctx, const int div_point,
1888                                   const int extra_lines, double mut_multiplier)
1889 {
1890 
1891   //cStats stats = m_world->GetStats();
1892   const int child_size = m_memory.GetSize() - div_point - extra_lines;
1893 
1894   // Make sure this divide will produce a viable offspring.
1895   const bool viable = Divide_CheckViable(ctx, div_point, child_size);
1896   if (viable == false) return false;
1897 
1898   // Since the divide will now succeed, set up the information to be sent
1899   // to the new organism
1900   Sequence& child_genome = m_organism->OffspringGenome().GetSequence();
1901   child_genome = m_memory.Crop(div_point, div_point + child_size);
1902   m_organism->OffspringGenome().SetHardwareType(GetType());
1903   m_organism->OffspringGenome().SetInstSet(m_inst_set->GetInstSetName());
1904 
1905   // Cut off everything in this memory past the divide point.
1906   m_memory.Resize(div_point);
1907 
1908   int totalMutations = 0;
1909   int mutations = 0;
1910   //    RScount = 0;
1911 
1912   bool fitTest = false;
1913 
1914   // Handle Divide Mutations...
1915   /*
1916    Do mutations until one of these conditions are satisified:
1917    we have resampled X times
1918    we have an offspring with the same number of muations as the first offspring
1919    that is not reverted
1920    the parent is steralized (usually means an implicit mutation)
1921    */
1922 
1923   mutations = totalMutations = Divide_DoMutations(ctx, mut_multiplier,1);
1924   for (int i = 0; i < 100; i++) {
1925     if (i > 0) {
1926       mutations = Divide_DoExactMutations(ctx, mut_multiplier,1);
1927       m_world->GetStats().IncResamplings();
1928     }
1929 
1930     fitTest = Divide_TestFitnessMeasures1(ctx);
1931     //if (mutations > 1 ) cerr << "Too Many mutations!!!!!!!!!!!!!!!" << endl;
1932     if (fitTest == false && mutations >= totalMutations) break;
1933 
1934   }
1935   // think about making this mutations == totalMuations - though this may be too hard...
1936   /*
1937    if (RScount > 2)
1938    cerr << "Resampled " << RScount << endl;
1939    */
1940   //org could not be resampled beneath the hard cap -- it is then steraalized
1941   if (fitTest/*RScount == 11*/) {
1942     m_organism->GetPhenotype().ChildFertile() = false;
1943     m_world->GetStats().IncFailedResamplings();
1944   }
1945 
1946   if (m_world->GetConfig().DIVIDE_METHOD.Get() != DIVIDE_METHOD_OFFSPRING) {
1947     // reset first time instruction costs
1948     for (int i = 0; i < m_inst_ft_cost.GetSize(); i++) {
1949       m_inst_ft_cost[i] = m_inst_set->GetFTCost(cInstruction(i));
1950     }
1951   }
1952 
1953   m_mal_active = false;
1954   if (m_world->GetConfig().DIVIDE_METHOD.Get() == DIVIDE_METHOD_SPLIT) {
1955     m_advance_ip = false;
1956   }
1957 
1958   // Activate the child, and do more work if the parent lives through the
1959   // birth.
1960   bool parent_alive = m_organism->ActivateDivide(ctx);
1961   if (parent_alive) {
1962     if (m_world->GetConfig().DIVIDE_METHOD.Get() == DIVIDE_METHOD_SPLIT) Reset(ctx);
1963   }
1964 
1965   return true;
1966 }
1967 
1968 /*
1969  Almost the same as Divide_Main, but only allows for one mutation
1970  on divde and resamples reverted offspring.
1971 
1972  RESAMPLING ONLY WORKS CORRECTLY WHEN ALL MUTIONS OCCUR ON DIVIDE!!
1973 
1974  AWC - 07/28/06
1975  */
Divide_Main2RS(cAvidaContext & ctx,const int div_point,const int extra_lines,double mut_multiplier)1976 bool cHardwareCPU::Divide_Main2RS(cAvidaContext& ctx, const int div_point,
1977                                   const int extra_lines, double mut_multiplier)
1978 {
1979 
1980   //cStats stats = m_world->GetStats();
1981   const int child_size = m_memory.GetSize() - div_point - extra_lines;
1982 
1983   // Make sure this divide will produce a viable offspring.
1984   const bool viable = Divide_CheckViable(ctx, div_point, child_size);
1985   if (viable == false) return false;
1986 
1987   // Since the divide will now succeed, set up the information to be sent
1988   // to the new organism
1989   Sequence& child_genome = m_organism->OffspringGenome().GetSequence();
1990   child_genome = m_memory.Crop(div_point, div_point + child_size);
1991   m_organism->OffspringGenome().SetHardwareType(GetType());
1992   m_organism->OffspringGenome().SetInstSet(m_inst_set->GetInstSetName());
1993 
1994   // Cut off everything in this memory past the divide point.
1995   m_memory.Resize(div_point);
1996 
1997   int totalMutations = 0;
1998   int mutations = 0;
1999   //    RScount = 0;
2000 
2001   bool fitTest = false;
2002 
2003 
2004   // Handle Divide Mutations...
2005   /*
2006    Do mutations until one of these conditions are satisified:
2007    we have resampled X times
2008    we have an offspring with the same number of muations as the first offspring
2009    that is not reverted
2010    the parent is steralized (usually means an implicit mutation)
2011    */
2012   for (int i = 0; i < 100; i++){
2013     if (i == 0){
2014       mutations = totalMutations = Divide_DoMutations(ctx, mut_multiplier,2);
2015     }
2016     else{
2017       Divide_DoExactMutations(ctx, mut_multiplier,mutations);
2018       m_world->GetStats().IncResamplings();
2019     }
2020 
2021     fitTest = Divide_TestFitnessMeasures(ctx);
2022     //if (mutations > 1 ) cerr << "Too Many mutations!!!!!!!!!!!!!!!" << endl;
2023     if (!fitTest && mutations >= totalMutations) break;
2024 
2025   }
2026   // think about making this mutations == totalMuations - though this may be too hard...
2027   /*
2028    if (RScount > 2)
2029    cerr << "Resampled " << RScount << endl;
2030    */
2031   //org could not be resampled beneath the hard cap -- it is then steraalized
2032   if (fitTest/*RScount == 11*/) {
2033     m_organism->GetPhenotype().ChildFertile() = false;
2034     m_world->GetStats().IncFailedResamplings();
2035   }
2036 
2037   if (m_world->GetConfig().DIVIDE_METHOD.Get() != DIVIDE_METHOD_OFFSPRING) {
2038     // reset first time instruction costs
2039     for (int i = 0; i < m_inst_ft_cost.GetSize(); i++) {
2040       m_inst_ft_cost[i] = m_inst_set->GetFTCost(cInstruction(i));
2041     }
2042   }
2043 
2044   m_mal_active = false;
2045   if (m_world->GetConfig().DIVIDE_METHOD.Get() == DIVIDE_METHOD_SPLIT) {
2046     m_advance_ip = false;
2047   }
2048 
2049   // Activate the child, and do more work if the parent lives through the
2050   // birth.
2051   bool parent_alive = m_organism->ActivateDivide(ctx);
2052   if (parent_alive) {
2053     if (m_world->GetConfig().DIVIDE_METHOD.Get() == DIVIDE_METHOD_SPLIT) Reset(ctx);
2054   }
2055 
2056   return true;
2057 }
2058 
2059 // Sets the current state of the hardware and also saves this state so
2060 //  that future Reset() calls will reset to that epigenetic state
InheritState(cHardwareBase & in_hardware)2061 void cHardwareCPU::InheritState(cHardwareBase& in_hardware)
2062 {
2063   m_epigenetic_state = true;
2064   cHardwareCPU& in_h = (cHardwareCPU&)in_hardware;
2065   const cLocalThread& thread = in_h.GetThread(in_h.GetCurThread());
2066   for (int i=0; i<NUM_REGISTERS; i++) {
2067     m_epigenetic_saved_reg[i] = thread.reg[i];
2068     m_threads[m_cur_thread].reg[i] = m_epigenetic_saved_reg[i];
2069   }
2070   m_epigenetic_saved_stack = thread.stack;
2071   m_threads[m_cur_thread].stack = m_epigenetic_saved_stack;
2072 }
2073 
2074 //////////////////////////
2075 // And the instructions...
2076 //////////////////////////
2077 
Inst_If0(cAvidaContext & ctx)2078 bool cHardwareCPU::Inst_If0(cAvidaContext& ctx)          // Execute next if ?bx? ==0.
2079 {
2080   const int reg_used = FindModifiedRegister(REG_BX);
2081   if (GetRegister(reg_used) != 0)  getIP().Advance();
2082   return true;
2083 }
2084 
Inst_IfNot0(cAvidaContext & ctx)2085 bool cHardwareCPU::Inst_IfNot0(cAvidaContext& ctx)       // Execute next if ?bx? != 0.
2086 {
2087   const int reg_used = FindModifiedRegister(REG_BX);
2088   if (GetRegister(reg_used) == 0)  getIP().Advance();
2089   return true;
2090 }
2091 
2092 // Same as Inst_If0, except AX is used by default, not BX
Inst_If0_defaultAX(cAvidaContext & ctx)2093 bool cHardwareCPU::Inst_If0_defaultAX(cAvidaContext& ctx)          // Execute next if ?ax? ==0.
2094 {
2095   const int reg_used = FindModifiedRegister(REG_AX);
2096   if (GetRegister(reg_used) != 0)  getIP().Advance();
2097   return true;
2098 }
2099 
2100 // Same as Inst_IfNot0, except AX is used by default, not BX
Inst_IfNot0_defaultAX(cAvidaContext & ctx)2101 bool cHardwareCPU::Inst_IfNot0_defaultAX(cAvidaContext& ctx)       // Execute next if ?ax? != 0.
2102 {
2103   const int reg_used = FindModifiedRegister(REG_AX);
2104   if (GetRegister(reg_used) == 0)  getIP().Advance();
2105   return true;
2106 }
2107 
Inst_IfEqu(cAvidaContext & ctx)2108 bool cHardwareCPU::Inst_IfEqu(cAvidaContext& ctx)      // Execute next if bx == ?cx?
2109 {
2110   const int op1 = FindModifiedRegister(REG_BX);
2111   const int op2 = FindNextRegister(op1);
2112   if (GetRegister(op1) != GetRegister(op2))  getIP().Advance();
2113   return true;
2114 }
2115 
Inst_IfNEqu(cAvidaContext & ctx)2116 bool cHardwareCPU::Inst_IfNEqu(cAvidaContext& ctx)     // Execute next if bx != ?cx?
2117 {
2118   const int op1 = FindModifiedRegister(REG_BX);
2119   const int op2 = FindNextRegister(op1);
2120   if (GetRegister(op1) == GetRegister(op2))  getIP().Advance();
2121   return true;
2122 }
2123 
Inst_IfGr0(cAvidaContext & ctx)2124 bool cHardwareCPU::Inst_IfGr0(cAvidaContext& ctx)       // Execute next if ?bx? ! < 0.
2125 {
2126   const int reg_used = FindModifiedRegister(REG_BX);
2127   if (GetRegister(reg_used) <= 0)  getIP().Advance();
2128   return true;
2129 }
2130 
Inst_IfGr(cAvidaContext & ctx)2131 bool cHardwareCPU::Inst_IfGr(cAvidaContext& ctx)       // Execute next if bx > ?cx?
2132 {
2133   const int op1 = FindModifiedRegister(REG_BX);
2134   const int op2 = FindNextRegister(op1);
2135   if (GetRegister(op1) <= GetRegister(op2))  getIP().Advance();
2136   return true;
2137 }
2138 
Inst_IfGrEqu0(cAvidaContext & ctx)2139 bool cHardwareCPU::Inst_IfGrEqu0(cAvidaContext& ctx)       // Execute next if ?bx? != 0.
2140 {
2141   const int reg_used = FindModifiedRegister(REG_BX);
2142   if (GetRegister(reg_used) < 0)  getIP().Advance();
2143   return true;
2144 }
2145 
Inst_IfGrEqu(cAvidaContext & ctx)2146 bool cHardwareCPU::Inst_IfGrEqu(cAvidaContext& ctx)       // Execute next if bx > ?cx?
2147 {
2148   const int op1 = FindModifiedRegister(REG_BX);
2149   const int op2 = FindNextRegister(op1);
2150   if (GetRegister(op1) < GetRegister(op2)) getIP().Advance();
2151   return true;
2152 }
2153 
Inst_IfLess0(cAvidaContext & ctx)2154 bool cHardwareCPU::Inst_IfLess0(cAvidaContext& ctx)       // Execute next if ?bx? != 0.
2155 {
2156   const int reg_used = FindModifiedRegister(REG_BX);
2157   if (GetRegister(reg_used) >= 0)  getIP().Advance();
2158   return true;
2159 }
2160 
Inst_IfLess(cAvidaContext & ctx)2161 bool cHardwareCPU::Inst_IfLess(cAvidaContext& ctx)       // Execute next if ?bx? < ?cx?
2162 {
2163   const int op1 = FindModifiedRegister(REG_BX);
2164   const int op2 = FindNextRegister(op1);
2165   if (GetRegister(op1) >=  GetRegister(op2))  getIP().Advance();
2166   return true;
2167 }
2168 
Inst_IfLsEqu0(cAvidaContext & ctx)2169 bool cHardwareCPU::Inst_IfLsEqu0(cAvidaContext& ctx)       // Execute next if ?bx? != 0.
2170 {
2171   const int reg_used = FindModifiedRegister(REG_BX);
2172   if (GetRegister(reg_used) > 0) getIP().Advance();
2173   return true;
2174 }
2175 
Inst_IfLsEqu(cAvidaContext & ctx)2176 bool cHardwareCPU::Inst_IfLsEqu(cAvidaContext& ctx)       // Execute next if bx > ?cx?
2177 {
2178   const int op1 = FindModifiedRegister(REG_BX);
2179   const int op2 = FindNextRegister(op1);
2180   if (GetRegister(op1) >  GetRegister(op2))  getIP().Advance();
2181   return true;
2182 }
2183 
Inst_IfBit1(cAvidaContext & ctx)2184 bool cHardwareCPU::Inst_IfBit1(cAvidaContext& ctx)
2185 {
2186   const int reg_used = FindModifiedRegister(REG_BX);
2187   if ((GetRegister(reg_used) & 1) == 0)  getIP().Advance();
2188   return true;
2189 }
2190 
Inst_IfANotEqB(cAvidaContext & ctx)2191 bool cHardwareCPU::Inst_IfANotEqB(cAvidaContext& ctx)     // Execute next if AX != BX
2192 {
2193   if (GetRegister(REG_AX) == GetRegister(REG_BX) )  getIP().Advance();
2194   return true;
2195 }
2196 
Inst_IfBNotEqC(cAvidaContext & ctx)2197 bool cHardwareCPU::Inst_IfBNotEqC(cAvidaContext& ctx)     // Execute next if BX != CX
2198 {
2199   if (GetRegister(REG_BX) == GetRegister(REG_CX) )  getIP().Advance();
2200   return true;
2201 }
2202 
Inst_IfANotEqC(cAvidaContext & ctx)2203 bool cHardwareCPU::Inst_IfANotEqC(cAvidaContext& ctx)     // Execute next if AX != BX
2204 {
2205   if (GetRegister(REG_AX) == GetRegister(REG_CX) )  getIP().Advance();
2206   return true;
2207 }
2208 
Inst_IfGrX(cAvidaContext & ctx)2209 bool cHardwareCPU::Inst_IfGrX(cAvidaContext& ctx)       // Execute next if BX > X; X value set according to NOP label
2210 {
2211   // Compares value in BX to a specific value.  The value to compare to is determined by the nop label as follows:
2212   //    no nop label (default): valueToCompare = 1; nop-A: valueToCompare = -1
2213   //                     nop-B: valueToCompare = 2; nop-C: valueToCompare =  4
2214   // @LMG 2/13/2009
2215 
2216   int valueToCompare = 1;
2217 
2218   if (m_inst_set->IsNop(getIP().GetNextInst())) {
2219     getIP().Advance();
2220     switch (m_inst_set->GetNopMod(getIP().GetInst())) {
2221 
2222       case REG_AX:
2223         valueToCompare = -1; break;
2224       case REG_BX:
2225         valueToCompare =  2; break;
2226       case REG_CX:
2227         valueToCompare =  4; break;
2228       default:
2229         valueToCompare =  1; break;
2230     }
2231     getIP().SetFlagExecuted();
2232 
2233   }
2234 
2235   if (GetRegister(REG_BX) <= valueToCompare)  getIP().Advance();
2236 
2237   return true;
2238 }
2239 
Inst_IfEquX(cAvidaContext & ctx)2240 bool cHardwareCPU::Inst_IfEquX(cAvidaContext& ctx)       // Execute next if BX == X; X value set according to NOP label
2241 {
2242   // Compares value in BX to a specific value.  The value to compare to is determined by the nop label as follows:
2243   //    no nop label (default): valueToCompare = 1; nop-A: valueToCompare = -1
2244   //                     nop-B: valueToCompare = 2; nop-C: valueToCompare =  4
2245   // @LMG 2/13/2009
2246 
2247   int valueToCompare = 1;
2248 
2249   if (m_inst_set->IsNop(getIP().GetNextInst())) {
2250     getIP().Advance();
2251     switch (m_inst_set->GetNopMod(getIP().GetInst())) {
2252 
2253       case REG_AX: valueToCompare = -1; break;
2254       case REG_BX: valueToCompare =  2; break;
2255       case REG_CX: valueToCompare =  4; break;
2256       default:     valueToCompare =  1; break;
2257     }
2258     getIP().SetFlagExecuted();
2259 
2260   }
2261 
2262   if (GetRegister(REG_BX) != valueToCompare)  getIP().Advance();
2263 
2264   return true;
2265 }
2266 
Inst_IfAboveResLevel(cAvidaContext & ctx)2267 bool cHardwareCPU::Inst_IfAboveResLevel(cAvidaContext& ctx)
2268 {
2269   const double resCrossoverLevel = 100;
2270 
2271   const cResourceLib& resLib = m_world->GetEnvironment().GetResourceLib();
2272   const tArray<double>& resource_count_array =  GetOrganism()->GetOrgInterface().GetResources(ctx);
2273   const cResourceCount& resource_count = m_world->GetPopulation().GetResourceCount();
2274 
2275   if (resource_count.GetSize() == 0) assert(false); // change to: return false;
2276 
2277   double pher_amount = 0;
2278   cResource* res = resLib.GetResource("pheromone");
2279 
2280   if (strncmp(resource_count.GetResName(res->GetID()), "pheromone", 9) == 0) {
2281     pher_amount += resource_count_array[res->GetID()];
2282   }
2283 
2284   if (pher_amount > resCrossoverLevel) {
2285     getIP().Advance();
2286   }
2287 
2288   return true;
2289 }
2290 
Inst_IfAboveResLevelEnd(cAvidaContext & ctx)2291 bool cHardwareCPU::Inst_IfAboveResLevelEnd(cAvidaContext& ctx)
2292 {
2293   const double resCrossoverLevel = 100;
2294 
2295   const cResourceLib& resLib = m_world->GetEnvironment().GetResourceLib();
2296 
2297   const tArray<double>& resource_count_array =  GetOrganism()->GetOrgInterface().GetResources(ctx);
2298   const cResourceCount& resource_count = m_world->GetPopulation().GetResourceCount();
2299 
2300   if (resource_count.GetSize() == 0) assert(false); // change to: return false;
2301 
2302   double pher_amount = 0;
2303   cResource* res = resLib.GetResource("pheromone");
2304 
2305   if (strncmp(resource_count.GetResName(res->GetID()), "pheromone", 9) == 0) {
2306     pher_amount += resource_count_array[res->GetID()];
2307   }
2308 
2309   if (pher_amount > resCrossoverLevel) {
2310     Else_TopHalf();
2311   }
2312 
2313   return true;
2314 }
2315 
Inst_IfNotAboveResLevel(cAvidaContext & ctx)2316 bool cHardwareCPU::Inst_IfNotAboveResLevel(cAvidaContext& ctx)
2317 {
2318   const double resCrossoverLevel = 100;
2319 
2320   const cResourceLib& resLib = m_world->GetEnvironment().GetResourceLib();
2321 
2322   const tArray<double>& resource_count_array =  GetOrganism()->GetOrgInterface().GetResources(ctx);
2323   const cResourceCount& resource_count = m_world->GetPopulation().GetResourceCount();
2324 
2325   if (resource_count.GetSize() == 0) assert(false); // change to: return false;
2326 
2327   double pher_amount = 0;
2328   cResource* res = resLib.GetResource("pheromone");
2329 
2330   if (strncmp(resource_count.GetResName(res->GetID()), "pheromone", 9) == 0) {
2331     pher_amount += resource_count_array[res->GetID()];
2332   }
2333 
2334   if (pher_amount <= resCrossoverLevel) {
2335     getIP().Advance();
2336   }
2337 
2338   return true;
2339 }
2340 
Inst_IfNotAboveResLevelEnd(cAvidaContext & ctx)2341 bool cHardwareCPU::Inst_IfNotAboveResLevelEnd(cAvidaContext& ctx)
2342 {
2343   const double resCrossoverLevel = 100;
2344 
2345   const cResourceLib& resLib = m_world->GetEnvironment().GetResourceLib();
2346   const tArray<double>& resource_count_array =  GetOrganism()->GetOrgInterface().GetResources(ctx);
2347   const cResourceCount& resource_count = m_world->GetPopulation().GetResourceCount();
2348 
2349   if (resource_count.GetSize() == 0) assert(false); // change to: return false;
2350 
2351   double pher_amount = 0;
2352   cResource* res = resLib.GetResource("pheromone");
2353 
2354   if (strncmp(resource_count.GetResName(res->GetID()), "pheromone", 9) == 0) {
2355     pher_amount += resource_count_array[res->GetID()];
2356   }
2357 
2358   if (pher_amount <= resCrossoverLevel) {
2359     Else_TopHalf();
2360   }
2361 
2362   return true;
2363 }
2364 
Inst_IfP0p125(cAvidaContext & ctx)2365 bool cHardwareCPU::Inst_IfP0p125(cAvidaContext& ctx)
2366 {
2367   if (m_world->GetRandom().P(0.875)) {
2368     getIP().Advance();
2369   }
2370 
2371   return true;
2372 }
2373 
2374 
Inst_IfP0p25(cAvidaContext & ctx)2375 bool cHardwareCPU::Inst_IfP0p25(cAvidaContext& ctx)
2376 {
2377   if (m_world->GetRandom().P(0.75)) {
2378     getIP().Advance();
2379   }
2380 
2381   return true;
2382 }
2383 
2384 
Inst_IfP0p50(cAvidaContext & ctx)2385 bool cHardwareCPU::Inst_IfP0p50(cAvidaContext& ctx)
2386 {
2387   if (m_world->GetRandom().P(0.5)) {
2388     getIP().Advance();
2389   }
2390 
2391   return true;
2392 }
2393 
2394 
Inst_IfP0p75(cAvidaContext & ctx)2395 bool cHardwareCPU::Inst_IfP0p75(cAvidaContext& ctx)
2396 {
2397   if (m_world->GetRandom().P(0.25)) {
2398     getIP().Advance();
2399   }
2400 
2401   return true;
2402 }
2403 
Inst_IfGerm(cAvidaContext & ctx)2404 bool cHardwareCPU::Inst_IfGerm(cAvidaContext& ctx)
2405 {
2406   if (!m_organism->IsGermline()) {
2407     getIP().Advance();
2408   }
2409 
2410   return true;
2411 }
2412 
Inst_IfSoma(cAvidaContext & ctx)2413 bool cHardwareCPU::Inst_IfSoma(cAvidaContext& ctx)
2414 {
2415   if (m_organism->IsGermline()) {
2416     getIP().Advance();
2417   }
2418 
2419   return true;
2420 }
2421 
2422 
Inst_JumpF(cAvidaContext & ctx)2423 bool cHardwareCPU::Inst_JumpF(cAvidaContext& ctx)
2424 {
2425   ReadLabel();
2426   GetLabel().Rotate(1, NUM_NOPS);
2427 
2428   // If there is no label, jump BX steps.
2429   if (GetLabel().GetSize() == 0) {
2430     GetActiveHead().Jump(GetRegister(REG_BX));
2431     return true;
2432   }
2433 
2434   // Otherwise, try to jump to the complement label.
2435   const cHeadCPU jump_location(FindLabel(1));
2436   if ( jump_location.GetPosition() != -1 ) {
2437     GetActiveHead().Set(jump_location);
2438     return true;
2439   }
2440 
2441   // If complement label was not found; record an error.
2442   m_organism->Fault(FAULT_LOC_JUMP, FAULT_TYPE_ERROR,
2443                     "jump-f: No complement label");
2444   return false;
2445 }
2446 
2447 
Inst_JumpB(cAvidaContext & ctx)2448 bool cHardwareCPU::Inst_JumpB(cAvidaContext& ctx)
2449 {
2450   ReadLabel();
2451   GetLabel().Rotate(1, NUM_NOPS);
2452 
2453   // If there is no label, jump BX steps.
2454   if (GetLabel().GetSize() == 0) {
2455     GetActiveHead().Jump(GetRegister(REG_BX));
2456     return true;
2457   }
2458 
2459   // otherwise jump to the complement label.
2460   const cHeadCPU jump_location(FindLabel(-1));
2461   if ( jump_location.GetPosition() != -1 ) {
2462     GetActiveHead().Set(jump_location);
2463     return true;
2464   }
2465 
2466   // If complement label was not found; record an error.
2467   m_organism->Fault(FAULT_LOC_JUMP, FAULT_TYPE_ERROR,
2468                     "jump-b: No complement label");
2469   return false;
2470 }
2471 
Inst_Call(cAvidaContext & ctx)2472 bool cHardwareCPU::Inst_Call(cAvidaContext& ctx)
2473 {
2474   // Put the starting location onto the stack
2475   const int location = getIP().GetPosition();
2476   StackPush(location);
2477 
2478   // Jump to the compliment label (or by the ammount in the bx register)
2479   ReadLabel();
2480   GetLabel().Rotate(1, NUM_NOPS);
2481 
2482   if (GetLabel().GetSize() == 0) {
2483     getIP().Jump(GetRegister(REG_BX));
2484     return true;
2485   }
2486 
2487   const cHeadCPU jump_location(FindLabel(1));
2488   if (jump_location.GetPosition() != -1) {
2489     getIP().Set(jump_location);
2490     return true;
2491   }
2492 
2493   // If complement label was not found; record an error.
2494   m_organism->Fault(FAULT_LOC_JUMP, FAULT_TYPE_ERROR,
2495                     "call: no complement label");
2496   return false;
2497 }
2498 
Inst_Return(cAvidaContext & ctx)2499 bool cHardwareCPU::Inst_Return(cAvidaContext& ctx)
2500 {
2501   getIP().Set(StackPop());
2502   return true;
2503 }
2504 
Inst_Throw(cAvidaContext & ctx)2505 bool cHardwareCPU::Inst_Throw(cAvidaContext& ctx)
2506 {
2507   // Only initialize this once to save some time...
2508   static cInstruction catch_inst = GetInstSet().GetInst(cStringUtil::Stringf("catch"));
2509 
2510   //Look for the label directly (no complement)
2511   ReadLabel();
2512 
2513   cHeadCPU search_head(getIP());
2514   int start_pos = search_head.GetPosition();
2515   search_head++;
2516 
2517   while (start_pos != search_head.GetPosition()) {
2518     // If we find a catch instruction, compare the NOPs following it
2519     if (search_head.GetInst() == catch_inst) {
2520       int catch_pos = search_head.GetPosition();
2521       search_head++;
2522 
2523       // Continue to examine the label after the catch
2524       //  (1) It ends (=> use the catch!)
2525       //  (2) It becomes longer than the throw label (=> use the catch!)
2526       //  (3) We find a NOP that doesnt match the throw (=> DON'T use the catch...)
2527 
2528       bool match = true;
2529       int size_matched = 0;
2530       while ( match && m_inst_set->IsNop(search_head.GetInst()) && (size_matched < GetLabel().GetSize()) ) {
2531         if ( GetLabel()[size_matched] != m_inst_set->GetNopMod( search_head.GetInst()) ) match = false;
2532         search_head++;
2533         size_matched++;
2534       }
2535 
2536       // We found a matching catch instruction
2537       if (match) {
2538         getIP().Set(catch_pos);
2539         m_advance_ip = false; // Don't automatically move the IP
2540         // so we mark the catch as executed.
2541         return true;
2542       }
2543 
2544       //If we advanced past NOPs during testing, retreat
2545       if ( !m_inst_set->IsNop(search_head.GetInst()) ) search_head--;
2546     }
2547     search_head.Advance();
2548   }
2549 
2550   return false;
2551 }
2552 
2553 
Inst_ThrowIfNot0(cAvidaContext & ctx)2554 bool cHardwareCPU::Inst_ThrowIfNot0(cAvidaContext& ctx)
2555 {
2556   if (GetRegister(REG_BX) == 0) return false;
2557   return Inst_Throw(ctx);
2558 }
2559 
Inst_ThrowIf0(cAvidaContext & ctx)2560 bool cHardwareCPU::Inst_ThrowIf0(cAvidaContext& ctx)
2561 {
2562   if (GetRegister(REG_BX) != 0) return false;
2563   return Inst_Throw(ctx);
2564 }
2565 
Inst_Goto(cAvidaContext & ctx)2566 bool cHardwareCPU::Inst_Goto(cAvidaContext& ctx)
2567 {
2568   // Only initialize this once to save some time...
2569   static cInstruction label_inst = GetInstSet().GetInst(cStringUtil::Stringf("label"));
2570 
2571   //Look for an EXACT label match after a 'label' instruction
2572   ReadLabel();
2573 
2574   cHeadCPU search_head(getIP());
2575   int start_pos = search_head.GetPosition();
2576   search_head++;
2577 
2578   while (start_pos != search_head.GetPosition()) {
2579     if (search_head.GetInst() == label_inst) {
2580       int label_pos = search_head.GetPosition();
2581       search_head++;
2582       int size_matched = 0;
2583       while ( size_matched < GetLabel().GetSize() ) {
2584         if ( !m_inst_set->IsNop(search_head.GetInst()) ) break;
2585         if ( GetLabel()[size_matched] != m_inst_set->GetNopMod( search_head.GetInst()) ) break;
2586         if ( !m_inst_set->IsNop(search_head.GetInst()) ) break;
2587 
2588         size_matched++;
2589         search_head++;
2590       }
2591 
2592       // We found a matching 'label' instruction only if the next
2593       // instruction (at the search head now) is also not a NOP
2594       if ( (size_matched == GetLabel().GetSize()) && !m_inst_set->IsNop(search_head.GetInst()) ) {
2595         getIP().Set(label_pos);
2596         m_advance_ip = false; // Don't automatically move the IP
2597         // so we mark the catch as executed.
2598         return true;
2599       }
2600 
2601       //If we advanced past NOPs during testing, retreat
2602       if ( !m_inst_set->IsNop(search_head.GetInst()) ) search_head--;
2603     }
2604     search_head++;
2605   }
2606 
2607   return false;
2608 }
2609 
2610 
Inst_GotoIfNot0(cAvidaContext & ctx)2611 bool cHardwareCPU::Inst_GotoIfNot0(cAvidaContext& ctx)
2612 {
2613   if (GetRegister(REG_BX) == 0) return false;
2614   return Inst_Goto(ctx);
2615 }
2616 
Inst_GotoIf0(cAvidaContext & ctx)2617 bool cHardwareCPU::Inst_GotoIf0(cAvidaContext& ctx)
2618 {
2619   if (GetRegister(REG_BX) != 0) return false;
2620   return Inst_Goto(ctx);
2621 }
2622 
2623 
Inst_Pop(cAvidaContext & ctx)2624 bool cHardwareCPU::Inst_Pop(cAvidaContext& ctx)
2625 {
2626   const int reg_used = FindModifiedRegister(REG_BX);
2627   GetRegister(reg_used) = StackPop();
2628   return true;
2629 }
2630 
Inst_Push(cAvidaContext & ctx)2631 bool cHardwareCPU::Inst_Push(cAvidaContext& ctx)
2632 {
2633   const int reg_used = FindModifiedRegister(REG_BX);
2634   StackPush(GetRegister(reg_used));
2635   return true;
2636 }
2637 
Inst_HeadPop(cAvidaContext & ctx)2638 bool cHardwareCPU::Inst_HeadPop(cAvidaContext& ctx)
2639 {
2640   const int head_used = FindModifiedHead(nHardware::HEAD_IP);
2641   getHead(head_used).Set(StackPop());
2642   return true;
2643 }
2644 
Inst_HeadPush(cAvidaContext & ctx)2645 bool cHardwareCPU::Inst_HeadPush(cAvidaContext& ctx)
2646 {
2647   const int head_used = FindModifiedHead(nHardware::HEAD_IP);
2648   StackPush(getHead(head_used).GetPosition());
2649   if (head_used == nHardware::HEAD_IP) {
2650     getHead(head_used).Set(getHead(nHardware::HEAD_FLOW));
2651     m_advance_ip = false;
2652   }
2653   return true;
2654 }
2655 
2656 
Inst_PopA(cAvidaContext & ctx)2657 bool cHardwareCPU::Inst_PopA(cAvidaContext& ctx) { GetRegister(REG_AX) = StackPop(); return true;}
Inst_PopB(cAvidaContext & ctx)2658 bool cHardwareCPU::Inst_PopB(cAvidaContext& ctx) { GetRegister(REG_BX) = StackPop(); return true;}
Inst_PopC(cAvidaContext & ctx)2659 bool cHardwareCPU::Inst_PopC(cAvidaContext& ctx) { GetRegister(REG_CX) = StackPop(); return true;}
2660 
Inst_PushA(cAvidaContext & ctx)2661 bool cHardwareCPU::Inst_PushA(cAvidaContext& ctx) { StackPush(GetRegister(REG_AX)); return true;}
Inst_PushB(cAvidaContext & ctx)2662 bool cHardwareCPU::Inst_PushB(cAvidaContext& ctx) { StackPush(GetRegister(REG_BX)); return true;}
Inst_PushC(cAvidaContext & ctx)2663 bool cHardwareCPU::Inst_PushC(cAvidaContext& ctx) { StackPush(GetRegister(REG_CX)); return true;}
2664 
Inst_SwitchStack(cAvidaContext & ctx)2665 bool cHardwareCPU::Inst_SwitchStack(cAvidaContext& ctx) { SwitchStack(); return true;}
Inst_FlipStack(cAvidaContext & ctx)2666 bool cHardwareCPU::Inst_FlipStack(cAvidaContext& ctx)   { StackFlip(); return true;}
2667 
Inst_Swap(cAvidaContext & ctx)2668 bool cHardwareCPU::Inst_Swap(cAvidaContext& ctx)
2669 {
2670   const int op1 = FindModifiedRegister(REG_BX);
2671   const int op2 = FindNextRegister(op1);
2672   Swap(GetRegister(op1), GetRegister(op2));
2673   return true;
2674 }
2675 
Inst_SwapAB(cAvidaContext & ctx)2676 bool cHardwareCPU::Inst_SwapAB(cAvidaContext& ctx)\
2677 {
2678   Swap(GetRegister(REG_AX), GetRegister(REG_BX)); return true;
2679 }
Inst_SwapBC(cAvidaContext & ctx)2680 bool cHardwareCPU::Inst_SwapBC(cAvidaContext& ctx)
2681 {
2682   Swap(GetRegister(REG_BX), GetRegister(REG_CX)); return true;
2683 }
Inst_SwapAC(cAvidaContext & ctx)2684 bool cHardwareCPU::Inst_SwapAC(cAvidaContext& ctx)
2685 {
2686   Swap(GetRegister(REG_AX), GetRegister(REG_CX)); return true;
2687 }
2688 
Inst_CopyReg(cAvidaContext & ctx)2689 bool cHardwareCPU::Inst_CopyReg(cAvidaContext& ctx)
2690 {
2691   const int src = FindModifiedRegister(REG_BX);
2692   const int dst = FindNextRegister(src);
2693   GetRegister(dst) = GetRegister(src);
2694   return true;
2695 }
2696 
Inst_CopyRegAB(cAvidaContext & ctx)2697 bool cHardwareCPU::Inst_CopyRegAB(cAvidaContext& ctx)
2698 {
2699   GetRegister(REG_AX) = GetRegister(REG_BX);   return true;
2700 }
Inst_CopyRegAC(cAvidaContext & ctx)2701 bool cHardwareCPU::Inst_CopyRegAC(cAvidaContext& ctx)
2702 {
2703   GetRegister(REG_AX) = GetRegister(REG_CX);   return true;
2704 }
Inst_CopyRegBA(cAvidaContext & ctx)2705 bool cHardwareCPU::Inst_CopyRegBA(cAvidaContext& ctx)
2706 {
2707   GetRegister(REG_BX) = GetRegister(REG_AX);   return true;
2708 }
Inst_CopyRegBC(cAvidaContext & ctx)2709 bool cHardwareCPU::Inst_CopyRegBC(cAvidaContext& ctx)
2710 {
2711   GetRegister(REG_BX) = GetRegister(REG_CX);   return true;
2712 }
Inst_CopyRegCA(cAvidaContext & ctx)2713 bool cHardwareCPU::Inst_CopyRegCA(cAvidaContext& ctx)
2714 {
2715   GetRegister(REG_CX) = GetRegister(REG_AX);   return true;
2716 }
Inst_CopyRegCB(cAvidaContext & ctx)2717 bool cHardwareCPU::Inst_CopyRegCB(cAvidaContext& ctx)
2718 {
2719   GetRegister(REG_CX) = GetRegister(REG_BX);   return true;
2720 }
2721 
Inst_Reset(cAvidaContext & ctx)2722 bool cHardwareCPU::Inst_Reset(cAvidaContext& ctx)
2723 {
2724   GetRegister(REG_AX) = 0;
2725   GetRegister(REG_BX) = 0;
2726   GetRegister(REG_CX) = 0;
2727   StackClear();
2728   m_last_cell_data = std::make_pair(false, 0);
2729   return true;
2730 }
2731 
Inst_ShiftR(cAvidaContext & ctx)2732 bool cHardwareCPU::Inst_ShiftR(cAvidaContext& ctx)
2733 {
2734   const int reg_used = FindModifiedRegister(REG_BX);
2735   GetRegister(reg_used) >>= 1;
2736   return true;
2737 }
2738 
Inst_ShiftL(cAvidaContext & ctx)2739 bool cHardwareCPU::Inst_ShiftL(cAvidaContext& ctx)
2740 {
2741   const int reg_used = FindModifiedRegister(REG_BX);
2742   GetRegister(reg_used) <<= 1;
2743   return true;
2744 }
2745 
Inst_Bit1(cAvidaContext & ctx)2746 bool cHardwareCPU::Inst_Bit1(cAvidaContext& ctx)
2747 {
2748   const int reg_used = FindModifiedRegister(REG_BX);
2749   GetRegister(reg_used) |=  1;
2750   return true;
2751 }
2752 
Inst_SetNum(cAvidaContext & ctx)2753 bool cHardwareCPU::Inst_SetNum(cAvidaContext& ctx)
2754 {
2755   ReadLabel();
2756   GetRegister(REG_BX) = GetLabel().AsInt(NUM_NOPS);
2757   return true;
2758 }
2759 
Inst_ValGrey(cAvidaContext & ctx)2760 bool cHardwareCPU::Inst_ValGrey(cAvidaContext& ctx) {
2761   ReadLabel();
2762   GetRegister(REG_BX) = GetLabel().AsIntGreyCode(NUM_NOPS);
2763   return true;
2764 }
2765 
Inst_ValDir(cAvidaContext & ctx)2766 bool cHardwareCPU::Inst_ValDir(cAvidaContext& ctx) {
2767   ReadLabel();
2768   GetRegister(REG_BX) = GetLabel().AsIntDirect(NUM_NOPS);
2769   return true;
2770 }
2771 
Inst_ValAddP(cAvidaContext & ctx)2772 bool cHardwareCPU::Inst_ValAddP(cAvidaContext& ctx) {
2773   ReadLabel();
2774   GetRegister(REG_BX) = GetLabel().AsIntAdditivePolynomial(NUM_NOPS);
2775   return true;
2776 }
2777 
Inst_ValFib(cAvidaContext & ctx)2778 bool cHardwareCPU::Inst_ValFib(cAvidaContext& ctx) {
2779   ReadLabel();
2780   GetRegister(REG_BX) = GetLabel().AsIntFib(NUM_NOPS);
2781   return true;
2782 }
2783 
Inst_ValPolyC(cAvidaContext & ctx)2784 bool cHardwareCPU::Inst_ValPolyC(cAvidaContext& ctx) {
2785   ReadLabel();
2786   GetRegister(REG_BX) = GetLabel().AsIntPolynomialCoefficent(NUM_NOPS);
2787   return true;
2788 }
2789 
Inst_Inc(cAvidaContext & ctx)2790 bool cHardwareCPU::Inst_Inc(cAvidaContext& ctx)
2791 {
2792   const int reg_used = FindModifiedRegister(REG_BX);
2793   GetRegister(reg_used) += 1;
2794   return true;
2795 }
2796 
Inst_Dec(cAvidaContext & ctx)2797 bool cHardwareCPU::Inst_Dec(cAvidaContext& ctx)
2798 {
2799   const int reg_used = FindModifiedRegister(REG_BX);
2800   GetRegister(reg_used) -= 1;
2801   return true;
2802 }
2803 
Inst_Zero(cAvidaContext & ctx)2804 bool cHardwareCPU::Inst_Zero(cAvidaContext& ctx)
2805 {
2806   const int reg_used = FindModifiedRegister(REG_BX);
2807   GetRegister(reg_used) = 0;
2808   return true;
2809 }
2810 
Inst_All1s(cAvidaContext & ctx)2811 bool cHardwareCPU::Inst_All1s(cAvidaContext& ctx)
2812 {
2813   const int reg_used = FindModifiedRegister(REG_BX);
2814   GetRegister(reg_used) = 0;
2815 
2816   for (int i=0; i< ((int) sizeof(int) * 8); i++) {
2817     GetRegister(reg_used) |= 1 << i;
2818   }
2819 
2820   return true;
2821 }
2822 
Inst_Neg(cAvidaContext & ctx)2823 bool cHardwareCPU::Inst_Neg(cAvidaContext& ctx)
2824 {
2825   const int src = FindModifiedRegister(REG_BX);
2826   const int dst = src;
2827   GetRegister(dst) = -GetRegister(src);
2828   return true;
2829 }
2830 
Inst_Square(cAvidaContext & ctx)2831 bool cHardwareCPU::Inst_Square(cAvidaContext& ctx)
2832 {
2833   const int src = FindModifiedRegister(REG_BX);
2834   const int dst = src;
2835   GetRegister(dst) = GetRegister(src) * GetRegister(src);
2836   return true;
2837 }
2838 
Inst_Sqrt(cAvidaContext & ctx)2839 bool cHardwareCPU::Inst_Sqrt(cAvidaContext& ctx)
2840 {
2841   const int src = FindModifiedRegister(REG_BX);
2842   const int dst = src;
2843   const int value = GetRegister(src);
2844   if (value > 1) GetRegister(dst) = static_cast<int>(sqrt(static_cast<double>(value)));
2845   else if (value < 0) {
2846     m_organism->Fault(FAULT_LOC_MATH, FAULT_TYPE_ERROR, "sqrt: value is negative");
2847     return false;
2848   }
2849   return true;
2850 }
2851 
Inst_Log(cAvidaContext & ctx)2852 bool cHardwareCPU::Inst_Log(cAvidaContext& ctx)
2853 {
2854   const int src = FindModifiedRegister(REG_BX);
2855   const int dst = src;
2856   const int value = GetRegister(src);
2857   if (value >= 1) GetRegister(dst) = static_cast<int>(log(static_cast<double>(value)));
2858   else if (value < 0) {
2859     m_organism->Fault(FAULT_LOC_MATH, FAULT_TYPE_ERROR, "log: value is negative");
2860     return false;
2861   }
2862   return true;
2863 }
2864 
Inst_Log10(cAvidaContext & ctx)2865 bool cHardwareCPU::Inst_Log10(cAvidaContext& ctx)
2866 {
2867   const int src = FindModifiedRegister(REG_BX);
2868   const int dst = src;
2869   const int value = GetRegister(src);
2870   if (value >= 1) GetRegister(dst) = static_cast<int>(log10(static_cast<double>(value)));
2871   else if (value < 0) {
2872     m_organism->Fault(FAULT_LOC_MATH, FAULT_TYPE_ERROR, "log10: value is negative");
2873     return false;
2874   }
2875   return true;
2876 }
2877 
Inst_Add(cAvidaContext & ctx)2878 bool cHardwareCPU::Inst_Add(cAvidaContext& ctx)
2879 {
2880   const int dst = FindModifiedRegister(REG_BX);
2881   const int op1 = REG_BX;
2882   const int op2 = REG_CX;
2883   GetRegister(dst) = GetRegister(op1) + GetRegister(op2);
2884   return true;
2885 }
2886 
Inst_Sub(cAvidaContext & ctx)2887 bool cHardwareCPU::Inst_Sub(cAvidaContext& ctx)
2888 {
2889   const int dst = FindModifiedRegister(REG_BX);
2890   const int op1 = REG_BX;
2891   const int op2 = REG_CX;
2892   GetRegister(dst) = GetRegister(op1) - GetRegister(op2);
2893   return true;
2894 }
2895 
Inst_Mult(cAvidaContext & ctx)2896 bool cHardwareCPU::Inst_Mult(cAvidaContext& ctx)
2897 {
2898   const int dst = FindModifiedRegister(REG_BX);
2899   const int op1 = REG_BX;
2900   const int op2 = REG_CX;
2901   GetRegister(dst) = GetRegister(op1) * GetRegister(op2);
2902   return true;
2903 }
2904 
Inst_Div(cAvidaContext & ctx)2905 bool cHardwareCPU::Inst_Div(cAvidaContext& ctx)
2906 {
2907   const int dst = FindModifiedRegister(REG_BX);
2908   const int op1 = REG_BX;
2909   const int op2 = REG_CX;
2910   if (GetRegister(op2) != 0) {
2911     if (0-INT_MAX > GetRegister(op1) && GetRegister(op2) == -1)
2912       m_organism->Fault(FAULT_LOC_MATH, FAULT_TYPE_ERROR, "div: Float exception");
2913     else
2914       GetRegister(dst) = GetRegister(op1) / GetRegister(op2);
2915   } else {
2916     m_organism->Fault(FAULT_LOC_MATH, FAULT_TYPE_ERROR, "div: dividing by 0");
2917     return false;
2918   }
2919   return true;
2920 }
2921 
Inst_Mod(cAvidaContext & ctx)2922 bool cHardwareCPU::Inst_Mod(cAvidaContext& ctx)
2923 {
2924   const int dst = FindModifiedRegister(REG_BX);
2925   const int op1 = REG_BX;
2926   const int op2 = REG_CX;
2927   if (GetRegister(op2) != 0) {
2928     GetRegister(dst) = GetRegister(op1) % GetRegister(op2);
2929   } else {
2930     m_organism->Fault(FAULT_LOC_MATH, FAULT_TYPE_ERROR, "mod: modding by 0");
2931     return false;
2932   }
2933   return true;
2934 }
2935 
2936 
Inst_Nand(cAvidaContext & ctx)2937 bool cHardwareCPU::Inst_Nand(cAvidaContext& ctx)
2938 {
2939   const int dst = FindModifiedRegister(REG_BX);
2940   const int op1 = REG_BX;
2941   const int op2 = REG_CX;
2942   GetRegister(dst) = ~(GetRegister(op1) & GetRegister(op2));
2943   return true;
2944 }
2945 
Inst_NandTreatable(cAvidaContext & ctx)2946 bool cHardwareCPU::Inst_NandTreatable(cAvidaContext& ctx)
2947 {
2948   /*
2949    if (!m_organism->GetDeme()->isTreatable() && m_world->GetRandom().P(probFail))
2950    return true;
2951 
2952    const int dst = FindModifiedRegister(REG_BX);
2953    const int op1 = REG_BX;
2954    const int op2 = REG_CX;
2955    GetRegister(dst) = ~(GetRegister(op1) & GetRegister(op2));
2956    */return true;
2957 }
2958 
Inst_Nor(cAvidaContext & ctx)2959 bool cHardwareCPU::Inst_Nor(cAvidaContext& ctx)
2960 {
2961   const int dst = FindModifiedRegister(REG_BX);
2962   const int op1 = REG_BX;
2963   const int op2 = REG_CX;
2964   GetRegister(dst) = ~(GetRegister(op1) | GetRegister(op2));
2965   return true;
2966 }
2967 
Inst_Or(cAvidaContext & ctx)2968 bool cHardwareCPU::Inst_Or(cAvidaContext& ctx)
2969 {
2970   const int dst = FindModifiedRegister(REG_BX);
2971   const int op1 = REG_BX;
2972   const int op2 = REG_CX;
2973   GetRegister(dst) = (GetRegister(op1) | GetRegister(op2));
2974   return true;
2975 }
2976 
Inst_And(cAvidaContext & ctx)2977 bool cHardwareCPU::Inst_And(cAvidaContext& ctx)
2978 {
2979   const int dst = FindModifiedRegister(REG_BX);
2980   const int op1 = REG_BX;
2981   const int op2 = REG_CX;
2982   GetRegister(dst) = (GetRegister(op1) & GetRegister(op2));
2983   return true;
2984 }
2985 
Inst_Not(cAvidaContext & ctx)2986 bool cHardwareCPU::Inst_Not(cAvidaContext& ctx)
2987 {
2988   const int src = FindModifiedRegister(REG_BX);
2989   const int dst = src;
2990   GetRegister(dst) = ~(GetRegister(src));
2991   return true;
2992 }
2993 
Inst_Order(cAvidaContext & ctx)2994 bool cHardwareCPU::Inst_Order(cAvidaContext& ctx)
2995 {
2996   const int op1 = REG_BX;
2997   const int op2 = REG_CX;
2998   if (GetRegister(op1) > GetRegister(op2)) {
2999     Swap(GetRegister(op1), GetRegister(op2));
3000   }
3001   return true;
3002 }
3003 
Inst_Xor(cAvidaContext & ctx)3004 bool cHardwareCPU::Inst_Xor(cAvidaContext& ctx)
3005 {
3006   const int dst = FindModifiedRegister(REG_BX);
3007   const int op1 = REG_BX;
3008   const int op2 = REG_CX;
3009   GetRegister(dst) = GetRegister(op1) ^ GetRegister(op2);
3010   return true;
3011 }
3012 
3013 // Set the bit in ?BX? specified in its complement register
Inst_Setbit(cAvidaContext & ctx)3014 bool cHardwareCPU::Inst_Setbit(cAvidaContext& ctx)
3015 {
3016   const int to_set = FindModifiedRegister(REG_BX);
3017   const int bit_reg = FindNextRegister(to_set);
3018 
3019   const int bit_to_set = max(0, GetRegister(bit_reg)) % (sizeof(int) * 8);
3020 
3021   GetRegister(to_set) |= 1 << bit_to_set;
3022 
3023   return true;
3024 }
3025 
3026 // Clear the bit in ?BX? specified in its complement register
Inst_Clearbit(cAvidaContext & ctx)3027 bool cHardwareCPU::Inst_Clearbit(cAvidaContext& ctx)
3028 {
3029   const int to_clear = FindModifiedRegister(REG_BX);
3030   const int bit_reg = FindNextRegister(to_clear);
3031 
3032   const int bit_to_clear = max(0, GetRegister(bit_reg)) % (sizeof(int) * 8);
3033 
3034   GetRegister(to_clear) &= ~(1 << bit_to_clear);
3035 
3036   return true;
3037 }
3038 
3039 
Inst_Copy(cAvidaContext & ctx)3040 bool cHardwareCPU::Inst_Copy(cAvidaContext& ctx)
3041 {
3042   const int op1 = REG_BX;
3043   const int op2 = REG_AX;
3044 
3045   const cHeadCPU from(this, GetRegister(op1));
3046   cHeadCPU to(this, GetRegister(op2) + GetRegister(op1));
3047 
3048   //checkNoMutList is for head to head kaboom experiments
3049   if (m_organism->TestCopyMut(ctx) && !(checkNoMutList(from))) {
3050     to.SetInst(m_inst_set->GetRandomInst(ctx));
3051     to.SetFlagMutated();  // Mark this instruction as mutated...
3052     to.SetFlagCopyMut();  // Mark this instruction as copy mut...
3053   } else {
3054     to.SetInst(from.GetInst());
3055     to.ClearFlagMutated();  // UnMark
3056     to.ClearFlagCopyMut();  // UnMark
3057   }
3058 
3059   to.SetFlagCopied();  // Set the copied flag.
3060   //  cpu_stats.mut_stats.copies_exec++;
3061   return true;
3062 }
3063 
Inst_ReadInst(cAvidaContext & ctx)3064 bool cHardwareCPU::Inst_ReadInst(cAvidaContext& ctx)
3065 {
3066   const int dst = FindModifiedRegister(REG_CX);
3067   const int src = REG_BX;
3068 
3069   const cHeadCPU from(this, GetRegister(src));
3070 
3071   // Dis-allowing mutations on read, for the moment (write only...)
3072   // @CAO This allows perfect error-correction...
3073   GetRegister(dst) = from.GetInst().GetOp();
3074   return true;
3075 }
3076 
Inst_WriteInst(cAvidaContext & ctx)3077 bool cHardwareCPU::Inst_WriteInst(cAvidaContext& ctx)
3078 {
3079   const int src = FindModifiedRegister(REG_CX);
3080   const int op1 = REG_BX;
3081   const int op2 = REG_AX;
3082 
3083   cHeadCPU to(this, GetRegister(op2) + GetRegister(op1));
3084   const int value = Mod(GetRegister(src), m_inst_set->GetSize());
3085 
3086   // Change value on a mutation... checkNoMutList is for head to head
3087     //kaboom experiments
3088   if (m_organism->TestCopyMut(ctx) && !(checkNoMutList(to))) {
3089     to.SetInst(m_inst_set->GetRandomInst(ctx));
3090     to.SetFlagMutated();      // Mark this instruction as mutated...
3091     to.SetFlagCopyMut();      // Mark this instruction as copy mut...
3092   } else {
3093     to.SetInst(cInstruction(value));
3094     to.ClearFlagMutated();     // UnMark
3095     to.ClearFlagCopyMut();     // UnMark
3096   }
3097 
3098   to.SetFlagCopied();  // Set the copied flag.
3099   return true;
3100 }
3101 
Inst_StackReadInst(cAvidaContext & ctx)3102 bool cHardwareCPU::Inst_StackReadInst(cAvidaContext& ctx)
3103 {
3104   const int reg_used = FindModifiedRegister(REG_CX);
3105   cHeadCPU from(this, GetRegister(reg_used));
3106   StackPush(from.GetInst().GetOp());
3107   return true;
3108 }
3109 
Inst_StackWriteInst(cAvidaContext & ctx)3110 bool cHardwareCPU::Inst_StackWriteInst(cAvidaContext& ctx)
3111 {
3112   const int dst = FindModifiedRegister(REG_BX);
3113   const int op1 = REG_AX;
3114   cHeadCPU to(this, GetRegister(op1) + GetRegister(dst));
3115   const int value = Mod(StackPop(), m_inst_set->GetSize());
3116 
3117   // Change value on a mutation... checkNoMutList is for head to head kaboom experiments
3118   if (m_organism->TestCopyMut(ctx) && !(checkNoMutList(to))) {
3119     to.SetInst(m_inst_set->GetRandomInst(ctx));
3120     to.SetFlagMutated();      // Mark this instruction as mutated...
3121     to.SetFlagCopyMut();      // Mark this instruction as copy mut...
3122   } else {
3123     to.SetInst(cInstruction(value));
3124     to.ClearFlagMutated();     // UnMark
3125     to.ClearFlagCopyMut();     // UnMark
3126   }
3127 
3128   to.SetFlagCopied();  // Set the copied flag.
3129   return true;
3130 }
3131 
Inst_Compare(cAvidaContext & ctx)3132 bool cHardwareCPU::Inst_Compare(cAvidaContext& ctx)
3133 {
3134   const int dst = FindModifiedRegister(REG_CX);
3135   const int op1 = REG_BX;
3136   const int op2 = REG_AX;
3137 
3138   cHeadCPU from(this, GetRegister(op1));
3139   cHeadCPU to(this, GetRegister(op2) + GetRegister(op1));
3140 
3141   // Compare is dangerous -- it can cause mutations!
3142     //checkNoMutList is for head to head kaboom experiments
3143   if (m_organism->TestCopyMut(ctx) && !(checkNoMutList(from))) {
3144     to.SetInst(m_inst_set->GetRandomInst(ctx));
3145     to.SetFlagMutated();      // Mark this instruction as mutated...
3146     to.SetFlagCopyMut();      // Mark this instruction as copy mut...
3147   }
3148 
3149   GetRegister(dst) = from.GetInst().GetOp() - to.GetInst().GetOp();
3150 
3151   return true;
3152 }
3153 
Inst_IfNCpy(cAvidaContext & ctx)3154 bool cHardwareCPU::Inst_IfNCpy(cAvidaContext& ctx)
3155 {
3156   const int op1 = REG_BX;
3157   const int op2 = REG_AX;
3158 
3159   const cHeadCPU from(this, GetRegister(op1));
3160   const cHeadCPU to(this, GetRegister(op2) + GetRegister(op1));
3161 
3162   // Allow for errors in this test...
3163   if (m_organism->TestCopyMut(ctx)) {
3164     if (from.GetInst() != to.GetInst()) getIP().Advance();
3165   } else {
3166     if (from.GetInst() == to.GetInst()) getIP().Advance();
3167   }
3168   return true;
3169 }
3170 
Inst_Allocate(cAvidaContext & ctx)3171 bool cHardwareCPU::Inst_Allocate(cAvidaContext& ctx)   // Allocate bx more space...
3172 {
3173   const int src = REG_BX;
3174   const int dst = REG_AX;
3175   const int size = m_memory.GetSize();
3176   if (Allocate_Main(ctx, GetRegister(src))) {
3177     GetRegister(dst) = size;
3178     return true;
3179   } else return false;
3180 }
3181 
Inst_Divide(cAvidaContext & ctx)3182 bool cHardwareCPU::Inst_Divide(cAvidaContext& ctx)
3183 {
3184   const int src = REG_AX;
3185   return Divide_Main(ctx, GetRegister(src));
3186 }
3187 
3188 /*
3189  Divide with resampling -- Same as regular divide but on reversions will be
3190  resampled after they are reverted.
3191 
3192  AWC 06/29/06
3193 
3194  */
3195 
Inst_DivideRS(cAvidaContext & ctx)3196 bool cHardwareCPU::Inst_DivideRS(cAvidaContext& ctx)
3197 {
3198   const int src = REG_AX;
3199   return Divide_MainRS(ctx, GetRegister(src));
3200 }
3201 
3202 
Inst_CDivide(cAvidaContext & ctx)3203 bool cHardwareCPU::Inst_CDivide(cAvidaContext& ctx)
3204 {
3205   return Divide_Main(ctx, m_memory.GetSize() / 2);
3206 }
3207 
Inst_CAlloc(cAvidaContext & ctx)3208 bool cHardwareCPU::Inst_CAlloc(cAvidaContext& ctx)
3209 {
3210   return Allocate_Main(ctx, m_memory.GetSize());
3211 }
3212 
Inst_MaxAlloc(cAvidaContext & ctx)3213 bool cHardwareCPU::Inst_MaxAlloc(cAvidaContext& ctx)   // Allocate maximal more
3214 {
3215   const int dst = REG_AX;
3216   const int cur_size = m_memory.GetSize();
3217   const int alloc_size = Min((int) (m_world->GetConfig().OFFSPRING_SIZE_RANGE.Get() * cur_size),
3218                              MAX_GENOME_LENGTH - cur_size);
3219   if (Allocate_Main(ctx, alloc_size)) {
3220     GetRegister(dst) = cur_size;
3221     return true;
3222   } else return false;
3223 }
3224 
3225 // Alloc and move write head if we're successful
Inst_MaxAllocMoveWriteHead(cAvidaContext & ctx)3226 bool cHardwareCPU::Inst_MaxAllocMoveWriteHead(cAvidaContext& ctx)   // Allocate maximal more
3227 {
3228   const int dst = REG_AX;
3229   const int cur_size = m_memory.GetSize();
3230   const int alloc_size = Min((int) (m_world->GetConfig().OFFSPRING_SIZE_RANGE.Get() * cur_size),
3231                              MAX_GENOME_LENGTH - cur_size);
3232   if (Allocate_Main(ctx, alloc_size)) {
3233     GetRegister(dst) = cur_size;
3234     getHead(nHardware::HEAD_WRITE).Set(cur_size);
3235     return true;
3236   } else return false;
3237 }
3238 
Inst_Transposon(cAvidaContext & ctx)3239 bool cHardwareCPU::Inst_Transposon(cAvidaContext& ctx)
3240 {
3241   ReadLabel();
3242   return true;
3243 }
3244 
Divide_DoTransposons(cAvidaContext & ctx)3245 void cHardwareCPU::Divide_DoTransposons(cAvidaContext& ctx)
3246 {
3247   // This only works if 'transposon' is in the current instruction set
3248   static bool transposon_in_use = GetInstSet().InstInSet(cStringUtil::Stringf("transposon"));
3249   if (!transposon_in_use) return;
3250 
3251   static cInstruction transposon_inst = GetInstSet().GetInst(cStringUtil::Stringf("transposon"));
3252   Sequence& child_genome = m_organism->OffspringGenome().GetSequence();
3253 
3254   // Count the number of transposons that are marked as executed
3255   int tr_count = 0;
3256   for (int i = 0; i < m_memory.GetSize(); i++) {
3257     if (m_memory.FlagExecuted(i) && (m_memory[i] == transposon_inst)) tr_count++;
3258   }
3259 
3260   for (int i = 0; i < tr_count; i++) {
3261     if (ctx.GetRandom().P(0.01)) {
3262       const unsigned int mut_line = ctx.GetRandom().GetUInt(child_genome.GetSize() + 1);
3263       child_genome.Insert(mut_line, transposon_inst);
3264     }
3265   }
3266 }
3267 
3268 
3269 // Inst_ReproDeme replicates a deme using cPopulation::ReplicateDeme.
3270 // It is similar to Inst_SpawnDeme, but the implementation of Inst_SpawnDeme doesn't contain many new deme-level replication features
Inst_ReproDeme(cAvidaContext & ctx)3271 bool cHardwareCPU::Inst_ReproDeme(cAvidaContext& ctx)
3272 {
3273   cDeme* sourceDeme = m_organism->GetOrgInterface().GetDeme();
3274   if (sourceDeme == NULL) return false; // in test CPU
3275 
3276   // this function will become to depend on a predicate, but I am still thinking of how to do this (BEB)
3277   sourceDeme->ReplicateDeme();
3278   return true;
3279 }
3280 
Inst_Repro(cAvidaContext & ctx)3281 bool cHardwareCPU::Inst_Repro(cAvidaContext& ctx)
3282 {
3283   // check if repro can replace an existing organism
3284   if (m_world->GetConfig().REPRO_METHOD.Get() == 0 && m_organism->IsNeighborCellOccupied()) {
3285     return false;
3286   }
3287 
3288   if (m_organism->GetPhenotype().GetCurBonus() < m_world->GetConfig().REQUIRED_BONUS.Get()) {
3289     return false;
3290   }
3291 
3292   // Setup child
3293   Sequence& child_genome = m_organism->OffspringGenome().GetSequence();
3294   child_genome = m_organism->GetGenome().GetSequence();
3295 
3296 
3297   m_organism->OffspringGenome().SetHardwareType(GetType());
3298   m_organism->OffspringGenome().SetInstSet(m_inst_set->GetInstSetName());
3299 
3300   // Do transposon movement and copying before other mutations
3301   Divide_DoTransposons(ctx);
3302 
3303   // Perform Copy Mutations...
3304   if (m_organism->GetCopyMutProb() > 0) { // Skip this if no mutations....
3305     //    for (int i = 0; i < m_memory.GetSize(); i++) {
3306     for (int i = 0; i < child_genome.GetSize(); i++) {
3307       //Need to check no_mut_insts for head to head kaboom experiments
3308       bool in_list = false;
3309       char test_inst = child_genome[i].GetSymbol();
3310       cString no_mut_list = m_world->GetConfig().NO_MUT_INSTS.Get();
3311       for (int j = 0; j < (int)strlen(no_mut_list); j++) {
3312         if ((char) no_mut_list[j] == test_inst) in_list = true;
3313       }
3314       if (m_organism->TestCopyMut(ctx) && !(in_list)) {
3315         child_genome[i] = m_inst_set->GetRandomInst(ctx);
3316       }
3317     }
3318   }
3319 
3320   //Need to clear the mutation steps, so that only most recent are there...
3321   child_genome.GetMutationSteps().Clear();
3322 
3323   //Perform divide mutations...
3324   Divide_DoMutations(ctx);
3325 
3326   // Check viability
3327   bool viable = Divide_CheckViable(ctx, m_organism->GetGenome().GetSize(), m_organism->OffspringGenome().GetSize(), 1);
3328   if (!viable) { return false; }
3329 
3330   // Many tests will require us to run the offspring through a test CPU;
3331   // this is, for example, to see if mutations need to be reverted or if
3332   // lineages need to be updated.
3333   Divide_TestFitnessMeasures(ctx);
3334 
3335   if (m_world->GetConfig().DIVIDE_METHOD.Get() != DIVIDE_METHOD_OFFSPRING) {
3336     // reset first time instruction costs
3337     for (int i = 0; i < m_inst_ft_cost.GetSize(); i++) {
3338       m_inst_ft_cost[i] = m_inst_set->GetFTCost(cInstruction(i));
3339     }
3340   }
3341 
3342   if (m_world->GetConfig().DIVIDE_METHOD.Get() == DIVIDE_METHOD_SPLIT) m_advance_ip = false;
3343 
3344   const bool parent_alive = m_organism->ActivateDivide(ctx);
3345 
3346   //Reset the parent
3347   if (parent_alive) {
3348     if (m_world->GetConfig().DIVIDE_METHOD.Get() == DIVIDE_METHOD_SPLIT) Reset(ctx);
3349   }
3350   return true;
3351 }
3352 
Inst_ReproSex(cAvidaContext & ctx)3353 bool cHardwareCPU::Inst_ReproSex(cAvidaContext& ctx)
3354 {
3355   m_organism->GetPhenotype().SetDivideSex(true);
3356   m_organism->GetPhenotype().SetCrossNum(1);
3357   return Inst_Repro(ctx);
3358 }
3359 
3360 
Inst_ReproGermFlag(cAvidaContext & ctx)3361 bool cHardwareCPU::Inst_ReproGermFlag(cAvidaContext& ctx)
3362 {
3363   // looks messy, but must occur in this order to ensure that failing repros don't trigger a germline addition
3364   bool res = Inst_Repro(ctx);
3365   if (res) Inst_JoinGermline(ctx);
3366   return res;
3367 }
3368 
Inst_TaskPutRepro(cAvidaContext & ctx)3369 bool cHardwareCPU::Inst_TaskPutRepro(cAvidaContext& ctx)
3370 {
3371   // Do normal IO, but don't zero register
3372   //Inst_TaskPut(ctx);
3373 
3374   const int reg_used = FindModifiedRegister(REG_BX);
3375   const int value = GetRegister(reg_used);
3376   // GetRegister(reg_used) = 0;
3377   m_organism->DoOutput(ctx, value);
3378 
3379   // Immediately attempt a repro
3380   return Inst_Repro(ctx);
3381 }
3382 
Inst_TaskPutResetInputsRepro(cAvidaContext & ctx)3383 bool cHardwareCPU::Inst_TaskPutResetInputsRepro(cAvidaContext& ctx)
3384 {
3385   // Do normal IO
3386   bool return_value = Inst_TaskPutResetInputs(ctx);
3387 
3388   // Immediately attempt a repro
3389   Inst_Repro(ctx);
3390 
3391   // return value of put since successful repro would wipe state anyway
3392   return return_value;
3393 }
3394 
3395 
3396 /* The organism can only replicate if the last task it performed is the task with ID 0 */
Inst_ConditionalRepro(cAvidaContext & ctx)3397 bool cHardwareCPU::Inst_ConditionalRepro(cAvidaContext& ctx)
3398 {
3399   if (m_organism->GetPhenotype().GetLastTaskID() == 0) {
3400     return Inst_Repro(ctx);
3401   }
3402   return false;
3403 }
3404 
Inst_SpawnDeme(cAvidaContext & ctx)3405 bool cHardwareCPU::Inst_SpawnDeme(cAvidaContext& ctx)
3406 {
3407   m_organism->SpawnDeme(ctx);
3408   return true;
3409 }
3410 
Inst_Kazi(cAvidaContext & ctx)3411 bool cHardwareCPU::Inst_Kazi(cAvidaContext& ctx)
3412 {
3413     assert(m_world->GetConfig().KABOOM_PROB.Get() != -1 || m_world->GetConfig().KABOOM_HAMMING.Get() != -1);
3414     //You can not have both kaboom_prob and kaboom_hamming set to adjustable because both must pull from the same register to be backwards compatible
3415   // Code changed to allow for AdjustableHD
3416   const int reg_used = FindModifiedRegister(REG_AX);
3417 
3418 
3419     double percent_prob = 1.0;
3420     int distance = -1;
3421   if ((int) m_world->GetConfig().KABOOM_PROB.Get() != -1 && (int) m_world->GetConfig().KABOOM_HAMMING.Get() == -1) {
3422     //Case where Probability is static and hamming distance is adjustable
3423     int get_reg_value = GetRegister(reg_used);
3424     //MAX_GENOME_SIZE and MIN_GENOME_SIZE should be set for these experiments, otherwise hamming distance doesn't make sense
3425     int genome_size = m_world->GetConfig().MAX_GENOME_SIZE.Get();
3426     percent_prob = (double) m_world->GetConfig().KABOOM_PROB.Get();
3427     distance = (get_reg_value % genome_size);
3428   } else if ((int) m_world->GetConfig().KABOOM_PROB.Get() != -1 && (int) m_world->GetConfig().KABOOM_HAMMING.Get() != -1) {
3429     //Case where both Probability and Hamming Distance are static
3430     percent_prob = (double) m_world->GetConfig().KABOOM_PROB.Get();
3431     distance = (int) m_world->GetConfig().KABOOM_HAMMING.Get();
3432   } else if ((int) m_world->GetConfig().KABOOM_PROB.Get() == -1 && (int) m_world->GetConfig().KABOOM_HAMMING.Get() != -1) {
3433     // Case where Probability is adjustable and Hamming distance isn't
3434     percent_prob = ((double) (GetRegister(reg_used) % 100)) / 100.0;
3435     distance = (int) m_world->GetConfig().KABOOM_HAMMING.Get();
3436     }
3437 
3438   if (ctx.GetRandom().P(percent_prob)) m_organism->Kaboom(distance, ctx);
3439   return true;
3440 }
3441 
Inst_Kazi5(cAvidaContext & ctx)3442 bool cHardwareCPU::Inst_Kazi5(cAvidaContext& ctx)
3443 {
3444     assert(m_world->GetConfig().KABOOM_PROB.Get() != -1 || m_world->GetConfig().KABOOM5_HAMMING.Get() != -1);
3445     const int reg_used = FindModifiedRegister(REG_AX);
3446     //These must always be set in the if, they can't both be adjustable, so don't do it
3447     int distance = -1;
3448     double percent_prob = 1.0;
3449     if ((int) m_world->GetConfig().KABOOM_PROB.Get() != -1 && (int) m_world->GetConfig().KABOOM5_HAMMING.Get() == -1) {
3450         //Case where Probability is static and hamming distance is adjustable
3451         int get_reg_value = GetRegister(reg_used);
3452         //MAX_GENOME_SIZE and MIN_GENOME_SIZE should be set for these experiments, otherwise hamming distance doesn't make sense
3453         int genome_size = m_world->GetConfig().MAX_GENOME_SIZE.Get();
3454         percent_prob = (double) m_world->GetConfig().KABOOM_PROB.Get();
3455         distance = (get_reg_value % genome_size);
3456     } else if ((int) m_world->GetConfig().KABOOM_PROB.Get() != -1 && (int) m_world->GetConfig().KABOOM5_HAMMING.Get() != -1) {
3457         //Case where both Probability and Hamming Distance are static
3458         percent_prob = (double) m_world->GetConfig().KABOOM_PROB.Get();
3459         distance = (int) m_world->GetConfig().KABOOM5_HAMMING.Get();
3460     } else if ((int) m_world->GetConfig().KABOOM_PROB.Get() == -1 && (int) m_world->GetConfig().KABOOM5_HAMMING.Get() != -1) {
3461         //Case where Probability is adjustable and Hamming distance isn't
3462         percent_prob = ((double) (GetRegister(reg_used) % 100)) / 100.0;
3463         distance = (int) m_world->GetConfig().KABOOM5_HAMMING.Get();
3464     }
3465 
3466     if ( ctx.GetRandom().P(percent_prob) ) m_organism->Kaboom(distance, ctx);
3467     return true;
3468 }
3469 
3470 
Inst_Sterilize(cAvidaContext & ctx)3471 bool cHardwareCPU::Inst_Sterilize(cAvidaContext& ctx)
3472 {
3473   m_organism->GetPhenotype().IsFertile() = false;
3474   return true;
3475 }
3476 
3477 
3478 
Inst_Die(cAvidaContext & ctx)3479 bool cHardwareCPU::Inst_Die(cAvidaContext& ctx)
3480 {
3481   m_organism->Die(ctx);
3482   return true;
3483 }
3484 
Inst_Poison(cAvidaContext & ctx)3485 bool cHardwareCPU::Inst_Poison(cAvidaContext& ctx)
3486 {
3487   double poison_multiplier = 1.0 - m_world->GetConfig().POISON_PENALTY.Get();
3488   m_organism->GetPhenotype().SetCurBonus(m_organism->GetPhenotype().GetCurBonus() * poison_multiplier);
3489   return true;
3490 }
3491 
3492 /* Similar to Kazi, this instructon probabilistically causes
3493  the organism to die. However, in this case it does so in
3494  order to win points for its deme and it does not take out
3495  any other organims. */
Inst_Suicide(cAvidaContext & ctx)3496 bool  cHardwareCPU::Inst_Suicide(cAvidaContext& ctx)
3497 {
3498   const int reg_used = FindModifiedRegister(REG_AX);
3499   double percentProb = ((double) (GetRegister(reg_used) % 100)) / 100.0;
3500   if (m_organism->GetDeme() == NULL)  return false; // in test CPU
3501   if ( ctx.GetRandom().P(percentProb) ) {
3502 
3503     // Add points as determined by config file to the deme.
3504     m_organism->GetDeme()->AddNumberOfPoints(m_world->GetConfig().DEMES_PROTECTION_POINTS.Get());
3505     m_organism->GetDeme()->AddSuicide();
3506     m_organism->Die(ctx);
3507   }
3508 
3509   return true;
3510 }
3511 
Inst_RelinquishEnergyToFutureDeme(cAvidaContext & ctx)3512 bool cHardwareCPU::Inst_RelinquishEnergyToFutureDeme(cAvidaContext& ctx)
3513 {
3514   double stored_energy = m_organism->GetPhenotype().GetStoredEnergy() * m_world->GetConfig().FRAC_ENERGY_RELINQUISH.Get();
3515   // put stored energy into testament pool for offspring deme
3516   cDeme* deme = m_organism->GetOrgInterface().GetDeme();
3517   if (deme == NULL) return false;  // in test CPU
3518   deme->IncreaseTotalEnergyTestament(stored_energy);
3519   m_world->GetStats().SumEnergyTestamentToFutureDeme().Add(stored_energy);
3520   m_organism->Die(ctx);
3521   return true;
3522 }
3523 
Inst_RelinquishEnergyToNeighborOrganisms(cAvidaContext & ctx)3524 bool cHardwareCPU::Inst_RelinquishEnergyToNeighborOrganisms(cAvidaContext& ctx)
3525 {
3526   double stored_energy = m_organism->GetPhenotype().GetStoredEnergy() * m_world->GetConfig().FRAC_ENERGY_RELINQUISH.Get();
3527   // put stored energy into toBeApplied energy pool of neighbor organisms
3528   int numOcuppiedNeighbors(0);
3529   for (int i = 0; i < m_organism->GetNeighborhoodSize(); i++) {
3530     if (m_organism->IsNeighborCellOccupied()) {
3531       // count neighboring organisms
3532       numOcuppiedNeighbors++;
3533     }
3534     m_organism->Rotate(1);
3535   }
3536 
3537   for (int i = 0; i < m_organism->GetNeighborhoodSize(); i++) {
3538     if (m_organism->IsNeighborCellOccupied()) {
3539       // give energy testament to neighboring organisms
3540       m_organism->GetNeighbor()->GetPhenotype().EnergyTestament(stored_energy/numOcuppiedNeighbors);
3541     }
3542     m_organism->Rotate(1);
3543   }
3544 
3545   m_world->GetStats().SumEnergyTestamentToNeighborOrganisms().Add(stored_energy);
3546   m_organism->Die(ctx);
3547 
3548   return true;
3549 }
3550 
Inst_RelinquishEnergyToOrganismsInDeme(cAvidaContext & ctx)3551 bool cHardwareCPU::Inst_RelinquishEnergyToOrganismsInDeme(cAvidaContext& ctx)
3552 {
3553   double stored_energy = m_organism->GetPhenotype().GetStoredEnergy() * m_world->GetConfig().FRAC_ENERGY_RELINQUISH.Get();
3554   // put stored energy into toBeApplied energy pool of neighbor organisms
3555 
3556   m_organism->DivideOrgTestamentAmongDeme(stored_energy);
3557   m_world->GetStats().SumEnergyTestamentToDemeOrganisms().Add(stored_energy);
3558   m_organism->Die(ctx);
3559   return true;
3560 }
3561 
3562 
3563 
Inst_TaskGet(cAvidaContext & ctx)3564 bool cHardwareCPU::Inst_TaskGet(cAvidaContext& ctx)
3565 {
3566   const int reg_used = FindModifiedRegister(REG_CX);
3567   const int value = m_organism->GetNextInput();
3568   GetRegister(reg_used) = value;
3569   m_organism->DoInput(value);
3570   return true;
3571 }
3572 
3573 
3574 // @JEB - this instruction does more than two "gets" together, it also resets the inputs
Inst_TaskGet2(cAvidaContext & ctx)3575 bool cHardwareCPU::Inst_TaskGet2(cAvidaContext& ctx)
3576 {
3577   // Randomize the inputs so they can't save numbers
3578   m_organism->GetOrgInterface().ResetInputs(ctx);   // Now re-randomize the inputs this organism sees
3579   m_organism->ClearInput();                         // Also clear their input buffers, or they can still claim
3580   // rewards for numbers no longer in their environment!
3581 
3582   const int reg_used_1 = FindModifiedRegister(REG_BX);
3583   const int reg_used_2 = FindNextRegister(reg_used_1);
3584 
3585   const int value1 = m_organism->GetNextInput();
3586   GetRegister(reg_used_1) = value1;
3587   m_organism->DoInput(value1);
3588 
3589   const int value2 = m_organism->GetNextInput();
3590   GetRegister(reg_used_2) = value2;
3591   m_organism->DoInput(value2);
3592 
3593   return true;
3594 }
3595 
Inst_TaskStackGet(cAvidaContext & ctx)3596 bool cHardwareCPU::Inst_TaskStackGet(cAvidaContext& ctx)
3597 {
3598   const int value = m_organism->GetNextInput();
3599   StackPush(value);
3600   m_organism->DoInput(value);
3601   return true;
3602 }
3603 
Inst_TaskStackLoad(cAvidaContext & ctx)3604 bool cHardwareCPU::Inst_TaskStackLoad(cAvidaContext& ctx)
3605 {
3606   // @DMB - TODO: this should look at the input_size...
3607   for (int i = 0; i < 3; i++) StackPush( m_organism->GetNextInput() );
3608   return true;
3609 }
3610 
Inst_TaskPut(cAvidaContext & ctx)3611 bool cHardwareCPU::Inst_TaskPut(cAvidaContext& ctx)
3612 {
3613   const int reg_used = FindModifiedRegister(REG_BX);
3614   const int value = GetRegister(reg_used);
3615   GetRegister(reg_used) = 0;
3616   m_organism->DoOutput(ctx, value);
3617   return true;
3618 }
3619 
Inst_TaskPutResetInputs(cAvidaContext & ctx)3620 bool cHardwareCPU::Inst_TaskPutResetInputs(cAvidaContext& ctx)
3621 {
3622   bool return_value = Inst_TaskPut(ctx);          // Do a normal put
3623   m_organism->GetOrgInterface().ResetInputs(ctx);   // Now re-randomize the inputs this organism sees
3624   m_organism->ClearInput();                         // Also clear their input buffers, or they can still claim
3625   // rewards for numbers no longer in their environment!
3626   return return_value;
3627 }
3628 
Inst_TaskIO(cAvidaContext & ctx)3629 bool cHardwareCPU::Inst_TaskIO(cAvidaContext& ctx)
3630 {
3631   const int reg_used = FindModifiedRegister(REG_BX);
3632 
3633   // Do the "put" component
3634   const int value_out = GetRegister(reg_used);
3635   m_organism->DoOutput(ctx, value_out);  // Check for tasks completed.
3636 
3637   // Do the "get" component
3638   const int value_in = m_organism->GetNextInput();
3639   GetRegister(reg_used) = value_in;
3640   m_organism->DoInput(value_in);
3641   return true;
3642 }
3643 
Inst_TaskIO_BonusCost(cAvidaContext & ctx,double bonus_cost)3644 bool cHardwareCPU::Inst_TaskIO_BonusCost(cAvidaContext& ctx, double bonus_cost)
3645 {
3646   // Levy the cost
3647   double new_bonus = m_organism->GetPhenotype().GetCurBonus() * (1 - bonus_cost);
3648   if (new_bonus < 0) new_bonus = 0;
3649   //keep the bonus positive or zero
3650   m_organism->GetPhenotype().SetCurBonus(new_bonus);
3651 
3652   return Inst_TaskIO(ctx);
3653 }
3654 
Inst_TaskIO_Feedback(cAvidaContext & ctx)3655 bool cHardwareCPU::Inst_TaskIO_Feedback(cAvidaContext& ctx)
3656 {
3657   const int reg_used = FindModifiedRegister(REG_BX);
3658 
3659   //check cur_bonus before the output
3660   double preOutputBonus = m_organism->GetPhenotype().GetCurBonus();
3661 
3662   // Do the "put" component
3663   const int value_out = GetRegister(reg_used);
3664   m_organism->DoOutput(ctx, value_out);  // Check for tasks completed.
3665 
3666   //check cur_merit after the output
3667   double postOutputBonus = m_organism->GetPhenotype().GetCurBonus();
3668 
3669 
3670   //push the effect of the IO on merit (+,0,-) to the active stack
3671 
3672   if (preOutputBonus > postOutputBonus){
3673     StackPush(-1);
3674   }
3675   else if (preOutputBonus == postOutputBonus){
3676     StackPush(0);
3677   }
3678   else if (preOutputBonus < postOutputBonus){
3679     StackPush(1);
3680   }
3681   else {
3682     assert(0);
3683     //Bollocks. There was an error.
3684   }
3685 
3686 
3687   // Do the "get" component
3688   const int value_in = m_organism->GetNextInput();
3689   GetRegister(reg_used) = value_in;
3690   m_organism->DoInput(value_in);
3691   return true;
3692 }
3693 
Inst_MatchStrings(cAvidaContext & ctx)3694 bool cHardwareCPU::Inst_MatchStrings(cAvidaContext& ctx)
3695 {
3696   if (m_executedmatchstrings) return false;
3697   m_organism->DoOutput(ctx, 357913941);
3698   m_executedmatchstrings = true;
3699 
3700   return true;
3701 }
3702 
Inst_Sell(cAvidaContext & ctx)3703 bool cHardwareCPU::Inst_Sell(cAvidaContext& ctx)
3704 {
3705   int search_label = GetLabel().AsInt(3) % MARKET_SIZE;
3706   int send_value = GetRegister(REG_BX);
3707   int sell_price = m_world->GetConfig().SELL_PRICE.Get();
3708   m_organism->SellValue(send_value, search_label, sell_price);
3709 
3710   return true;
3711 }
3712 
Inst_Buy(cAvidaContext & ctx)3713 bool cHardwareCPU::Inst_Buy(cAvidaContext& ctx)
3714 {
3715   int search_label = GetLabel().AsInt(3) % MARKET_SIZE;
3716   int buy_price = m_world->GetConfig().BUY_PRICE.Get();
3717   GetRegister(REG_BX) = m_organism->BuyValue(search_label, buy_price);
3718 
3719   return true;
3720 }
3721 
Inst_Send(cAvidaContext & ctx)3722 bool cHardwareCPU::Inst_Send(cAvidaContext& ctx)
3723 {
3724   const int reg_used = FindModifiedRegister(REG_BX);
3725   m_organism->SendValue(GetRegister(reg_used));
3726   GetRegister(reg_used) = 0;
3727 
3728   return true;
3729 }
3730 
Inst_Receive(cAvidaContext & ctx)3731 bool cHardwareCPU::Inst_Receive(cAvidaContext& ctx)
3732 {
3733   const int reg_used = FindModifiedRegister(REG_BX);
3734   GetRegister(reg_used) = m_organism->ReceiveValue();
3735 
3736   return true;
3737 }
3738 
Inst_SenseLog2(cAvidaContext & ctx)3739 bool cHardwareCPU::Inst_SenseLog2(cAvidaContext& ctx)
3740 {
3741   return DoSense(ctx, 0, 2);
3742 }
3743 
Inst_SenseUnit(cAvidaContext & ctx)3744 bool cHardwareCPU::Inst_SenseUnit(cAvidaContext& ctx)
3745 {
3746   return DoSense(ctx, 1, 1);
3747 }
3748 
Inst_SenseMult100(cAvidaContext & ctx)3749 bool cHardwareCPU::Inst_SenseMult100(cAvidaContext& ctx)
3750 {
3751   return DoSense(ctx, 1, 100);
3752 }
3753 
DoSense(cAvidaContext & ctx,int conversion_method,double base)3754 bool cHardwareCPU::DoSense(cAvidaContext& ctx, int conversion_method, double base)
3755 {
3756   // Returns the amount of a resource or resources
3757   // specified by modifying NOPs into register BX
3758   const tArray<double> res_count = m_organism->GetOrgInterface().GetResources(ctx) +
3759   m_organism->GetOrgInterface().GetDemeResources(m_organism->GetOrgInterface().GetDemeID(), ctx);
3760 
3761   // Arbitrarily set to BX since the conditional instructions use this directly.
3762   int reg_to_set = REG_BX;
3763 
3764   // There are no resources, return
3765   if (res_count.GetSize() == 0) return false;
3766 
3767   // Only recalculate logs if these values have changed
3768   static int last_num_resources = 0;
3769   static int max_label_length = 0;
3770   int num_nops = GetInstSet().GetNumNops();
3771 
3772   if ((last_num_resources != res_count.GetSize()))
3773   {
3774     max_label_length = (int) ceil(log((double)res_count.GetSize())/log((double)num_nops));
3775     last_num_resources = res_count.GetSize();
3776   }
3777 
3778   // Convert modifying NOPs to the index of the resource.
3779   // If there are fewer than the number of NOPs required
3780   // to uniquely specify a resource, then add together
3781   // a subset of resources (motivation: regulation can evolve
3782   // to be more specific if there is an advantage)
3783 
3784   // Find the maximum number of NOPs needed to specify this number of resources
3785   // Note: It's a bit wasteful to recalculate this every time and organisms will
3786   // definitely be confused if the number of resources changes during a run
3787   // because their mapping to resources will be disrupted
3788 
3789   // Attempt to read a label with this maximum length
3790   ReadLabel(max_label_length);
3791 
3792   // Find the length of the label that we actually obtained (max is max_reg_needed)
3793   int real_label_length = GetLabel().GetSize();
3794 
3795   // Start and end labels to define the start and end indices of
3796   // resources that we need to add together
3797   cCodeLabel start_label = cCodeLabel(GetLabel());
3798   cCodeLabel   end_label = cCodeLabel(GetLabel());
3799 
3800   for (int i = 0; i < max_label_length - real_label_length; i++) {
3801     start_label.AddNop(0);
3802     end_label.AddNop(num_nops-1);
3803   }
3804 
3805   int start_index = start_label.AsInt(num_nops);
3806   int   end_index =   end_label.AsInt(num_nops);
3807 
3808   // If the label refers to ONLY resources that
3809   // do not exist, then the operation fails
3810   if (start_index >= res_count.GetSize()) return false;
3811 
3812   // Otherwise sum all valid resources that it might refer to
3813   // (this will only be ONE if the label was of the maximum length).
3814   int resource_result = 0;
3815   double dresource_result = 0;
3816   for (int i = start_index; i <= end_index; i++) {
3817     // if it's a valid resource
3818     if (i < res_count.GetSize()) {
3819       if (conversion_method == 0) { // Log
3820         // for log, add together and then take log
3821         dresource_result += (double) res_count[i];
3822       }
3823       else if (conversion_method == 1) { // Addition of multiplied resource amount
3824         int add_amount = (int) (res_count[i] * base);
3825         // Do some range checking to make sure we don't overflow
3826         resource_result = (INT_MAX - resource_result <= add_amount) ? INT_MAX : resource_result + add_amount;
3827       }
3828     }
3829   }
3830 
3831   // Take the log after adding resource amounts together! This way a zero can be assigned to INT_MIN
3832   if (conversion_method == 0) { // Log2
3833     // You really shouldn't be using the log method if you can get to zero resources
3834     if (dresource_result == 0.0) {
3835       resource_result = INT_MIN;
3836     }
3837     else {
3838       resource_result = (int)(log(dresource_result)/log(base));
3839     }
3840   }
3841 
3842   //Dump this value into an arbitrary register: BX
3843   GetRegister(reg_to_set) = resource_result;
3844 
3845   //We have to convert this to a different index that includes all degenerate labels possible: shortest to longest
3846   int sensed_index = 0;
3847   int on = 1;
3848   for (int i = 0; i < real_label_length; i++) {
3849     sensed_index += on;
3850     on *= num_nops;
3851   }
3852   sensed_index+= GetLabel().AsInt(num_nops);
3853   m_organism->GetPhenotype().IncSenseCount(sensed_index);
3854 
3855   return true;
3856 
3857   // Note that we are converting <double> resources to <int> register values
3858 }
3859 
3860 
Inst_SenseResource0(cAvidaContext & ctx)3861 bool cHardwareCPU::Inst_SenseResource0(cAvidaContext& ctx)
3862 {
3863   return DoSenseResourceX(REG_BX, m_organism->GetCellID(), 0, ctx);
3864 }
3865 
Inst_SenseResource1(cAvidaContext & ctx)3866 bool cHardwareCPU::Inst_SenseResource1(cAvidaContext& ctx)
3867 {
3868   return DoSenseResourceX(REG_BX, m_organism->GetCellID(), 1, ctx);
3869 }
3870 
Inst_SenseResource2(cAvidaContext & ctx)3871 bool cHardwareCPU::Inst_SenseResource2(cAvidaContext& ctx)
3872 {
3873   return DoSenseResourceX(REG_BX, m_organism->GetCellID(), 2, ctx);
3874 }
3875 
Inst_SenseFacedResource0(cAvidaContext & ctx)3876 bool cHardwareCPU::Inst_SenseFacedResource0(cAvidaContext& ctx)
3877 {
3878   return DoSenseResourceX(REG_BX, m_world->GetPopulation().GetCell(m_organism->GetCellID()).GetCellFaced().GetID(), 0, ctx);
3879 }
3880 
Inst_SenseFacedResource1(cAvidaContext & ctx)3881 bool cHardwareCPU::Inst_SenseFacedResource1(cAvidaContext& ctx)
3882 {
3883   return DoSenseResourceX(REG_BX, m_world->GetPopulation().GetCell(m_organism->GetCellID()).GetCellFaced().GetID(), 1, ctx);
3884 }
3885 
Inst_SenseFacedResource2(cAvidaContext & ctx)3886 bool cHardwareCPU::Inst_SenseFacedResource2(cAvidaContext& ctx)
3887 {
3888   return DoSenseResourceX(REG_BX, m_world->GetPopulation().GetCell(m_organism->GetCellID()).GetCellFaced().GetID(), 2, ctx);
3889 }
3890 
3891 
DoSenseResourceX(int reg_to_set,int cell_id,int resid,cAvidaContext & ctx)3892 bool cHardwareCPU::DoSenseResourceX(int reg_to_set, int cell_id, int resid, cAvidaContext& ctx)
3893 {
3894   assert(resid >= 0);
3895 
3896   cPopulation& pop = m_world->GetPopulation();
3897 
3898   const tArray<double> & res_count = pop.GetCellResources(cell_id, ctx) +
3899   pop.GetDemeCellResources(pop.GetCell(cell_id).GetDemeID(), cell_id, ctx);
3900 
3901   // Make sure we have the resource requested
3902   if (resid >= res_count.GetSize()) return false;
3903 
3904   GetRegister(reg_to_set) = (int) res_count[resid];
3905 
3906   return true;
3907 
3908 }
3909 
Inst_SenseResourceID(cAvidaContext & ctx)3910 bool cHardwareCPU::Inst_SenseResourceID(cAvidaContext& ctx)
3911 {
3912   const tArray<double> res_count = m_organism->GetOrgInterface().GetResources(ctx);
3913   int reg_to_set = FindModifiedRegister(REG_BX);
3914   double max_resource = 0.0;
3915   // if more than one resource is available, return the resource ID with the most available in this spot (note that, with global resources, the GLOBAL total will evaluated)
3916   for (int i = 0; i < res_count.GetSize(); i++) {
3917     if (res_count[i] > max_resource) {
3918       max_resource = res_count[i];
3919       GetRegister(reg_to_set) = i;
3920     }
3921   }
3922   return true;
3923 }
3924 
Inst_SenseOpinionResourceQuantity(cAvidaContext & ctx)3925 bool cHardwareCPU::Inst_SenseOpinionResourceQuantity(cAvidaContext& ctx)
3926 {
3927   const tArray<double> res_count = m_organism->GetOrgInterface().GetResources(ctx);
3928   // check if this is a valid group
3929   if(m_organism->GetOrgInterface().HasOpinion(m_organism)) {
3930     int opinion = m_organism->GetOpinion().first;
3931     int res_opinion = (int) (res_count[opinion] * 100 + 0.5);
3932     int reg_to_set = FindModifiedRegister(REG_BX);
3933     GetRegister(reg_to_set) = res_opinion;
3934   }
3935   return true;
3936 }
3937 
3938 /* Must be nop-modified.
3939  * Places the number of resources in the group either +1 or -1 in register BX,
3940  * wrapping from the top group back to group 1 (skipping 0),
3941  * +1 group if the nop register has a positive number
3942  * -1 group if the nop register has a negative number.
3943  */
Inst_SenseNextResLevel(cAvidaContext & ctx)3944 bool cHardwareCPU::Inst_SenseNextResLevel(cAvidaContext& ctx)
3945 {
3946   // Check for an opinion.
3947   if (!m_organism->GetOrgInterface().HasOpinion(m_organism)) return false;
3948   if (m_world->GetConfig().USE_FORM_GROUPS.Get() != 2) return false;
3949   int opinion = m_organism->GetOpinion().first;
3950 
3951   const int num_groups = m_organism->GetOrgInterface().GetResources(ctx).GetSize();
3952   if (num_groups <= 2) return false;
3953 
3954   // If not nop-modified, fails to execute.
3955   if (!(m_inst_set->IsNop(getIP().GetNextInst()))) return false;
3956   // Retreives the value from the nop-modifying register.
3957   const int nop_register = FindModifiedRegister(REG_BX);
3958   int register_value = GetRegister(nop_register);
3959   if (register_value == 0) return false;
3960 
3961   const tArray<double> res_count = m_organism->GetOrgInterface().GetResources(ctx);
3962   if (opinion == (num_groups - 1)) {
3963     if (register_value > 0) GetRegister(REG_BX) = (int) (res_count[1] * 100 + 0.5);
3964     else if (register_value < 0) GetRegister(REG_BX) = (int) (res_count[opinion - 1] * 100 + 0.5);
3965   }
3966   else if ((opinion == 1) || (opinion == 0)) {
3967     if (register_value > 0) GetRegister(REG_BX) = (int) (res_count[opinion + 1] * 100 + 0.5);
3968     else if (register_value < 0) GetRegister(REG_BX) = (int) (res_count[num_groups - 1] * 100 + 0.5);
3969   }
3970   else if ((opinion != (num_groups - 1)) && (opinion != 1) && (opinion != 0)) {
3971     if (register_value > 0) GetRegister(REG_BX) = (int) (res_count[opinion + 1] * 100 + 0.5);
3972     else if (register_value < 0) GetRegister(REG_BX) = (int) (res_count[opinion - 1] * 100 + 0.5);
3973   }
3974   return true;
3975 }
3976 
Inst_SenseDiffFaced(cAvidaContext & ctx)3977 bool cHardwareCPU::Inst_SenseDiffFaced(cAvidaContext& ctx)
3978 {
3979   const tArray<double> res_count = m_organism->GetOrgInterface().GetResources(ctx);
3980   if(m_organism->GetOrgInterface().HasOpinion(m_organism)) {
3981     int opinion = m_organism->GetOpinion().first;
3982     int reg_to_set = FindModifiedRegister(REG_BX);
3983     double faced_res = m_organism->GetOrgInterface().GetFacedCellResources(ctx)[opinion];
3984     // return % change
3985     int res_diff = 0;
3986     if (res_count[opinion] == 0) res_diff = (int) faced_res;
3987     else res_diff = (int) (((faced_res - res_count[opinion])/res_count[opinion]) * 100 + 0.5);
3988     GetRegister(reg_to_set) = res_diff;
3989   }
3990   return true;
3991 }
3992 
Inst_SenseFacedHabitat(cAvidaContext & ctx)3993 bool cHardwareCPU::Inst_SenseFacedHabitat(cAvidaContext& ctx)
3994 {
3995   int reg_to_set = FindModifiedRegister(REG_BX);
3996 
3997   // get the resource library
3998   const cResourceLib& resource_lib = m_world->GetEnvironment().GetResourceLib();
3999 
4000   // get the destination cell resource levels
4001   tArray<double> cell_resource_levels = m_organism->GetOrgInterface().GetFacedCellResources(ctx);
4002 
4003   // check for any habitats ahead that affect movement, returning the most 'severe' habitat type
4004   // are there any barrier resources in the faced cell
4005   for (int i = 0; i < cell_resource_levels.GetSize(); i++) {
4006     if (resource_lib.GetResource(i)->GetHabitat() == 2 && cell_resource_levels[i] > 0) {
4007       GetRegister(reg_to_set) = 2;
4008       return true;
4009     }
4010   }
4011   // if no barriers, are there any hills in the faced cell
4012   for (int i = 0; i < cell_resource_levels.GetSize(); i++) {
4013     if (resource_lib.GetResource(i)->GetHabitat() == 1 && cell_resource_levels[i] > 0) {
4014       GetRegister(reg_to_set) = 1;
4015       return true;
4016     }
4017   }
4018   // if no barriers or hills, we return a 0 to indicate clear sailing
4019   GetRegister(reg_to_set) = 0;
4020   return true;
4021 }
4022 
4023 /* Convert modifying NOPs to the index of a resource.
4024  *
4025  * When the specification does not map to exactly one resource (either because the
4026  * specification does not have enough nops to fully specify, or because the number of
4027  * resources is not a power of the number of nops), choose randomly among the resources
4028  * covered by the specification.  The random choice is weighted by how much of the
4029  * resource is covered by the specification.
4030  *
4031  * For example, in a 3-nop 4-resource system:
4032  * A -> 75% chance resouce 0, 25% chance resource 1
4033  * AA and AB -> 100% chance resource 0
4034  * AC -> 75% chance resource 0, 25% chance resource 1
4035  *
4036  * Originally inspired by Jeff B.'s DoSense(); meant to be a helper function for
4037  * the various collect instructions, and anything else that wants to use this type
4038  * of resource NOP-specification.
4039  */
FindModifiedResource(cAvidaContext & ctx,int & spec_id)4040 int cHardwareCPU::FindModifiedResource(cAvidaContext& ctx, int& spec_id)
4041 {
4042   int num_resources = m_organism->GetOrgInterface().GetResources(ctx).GetSize();
4043 
4044   //if there are no resources, translation cannot be successful; return false
4045   if (num_resources <= 0)
4046   {return -1;}
4047 
4048   //calculate the maximum number of NOPs necessary to completely specify a resource
4049   int num_nops = GetInstSet().GetNumNops();
4050   int max_label_length = (int)(ceil(log((double)num_resources) / log((double)num_nops)));
4051 
4052   //attempt to read a label of the maximum length
4053   ReadLabel(max_label_length);
4054 
4055   //find the length of the label that was actually read
4056   int real_label_length = GetLabel().GetSize();
4057 
4058   // save the specification id
4059   spec_id = GetLabel().AsIntUnique(num_nops);
4060 
4061   /* Find the resource specified by the label.
4062    * If the specification is not complete, pick a resource from the range specified.
4063    * If the range covers resources unequally, this is taken into account.
4064    */
4065 
4066   // translate the specification into a number
4067   int label_int = GetLabel().AsInt(num_nops);
4068 
4069   // find the chunk of a unit range covered by the specification
4070   double chunk_size = 1.0 / pow(double(num_nops), real_label_length);
4071 
4072 
4073   // choose a point in the range
4074   double resource_approx = label_int * chunk_size + ctx.GetRandom().GetDouble(chunk_size);
4075 
4076   // translate it into a resource bin
4077   int bin_used = floor(resource_approx * num_resources);
4078 
4079   return bin_used;
4080 }
4081 
4082 /* Helper function to reduce code redundancy in the Inst_Collect variations,
4083  * including Inst_Destroy.
4084  * Calls FindModifiedResource() to decide which resource to collect, logs which
4085  * specification was used, then calls DoActualCollect() to do the environmental
4086  * resource removal and/or internal resource addition.
4087  *
4088  * env_remove    - specifies whether the collected resources should be removed from
4089  *                 the environment
4090  * internal_add  - specifies whether the collected resources should be added to
4091  *                 the organism's internal resources.
4092  * probabilistic - specifies whether the chance of collection success should be based on
4093  *                 the amount of resource in the environment.
4094  * unit          - specifies whether collection uses the ABSORB_RESOURCE_FRACTION
4095  *                 configuration or always collects 1 unit of resource.
4096  */
DoCollect(cAvidaContext & ctx,bool env_remove,bool internal_add,bool probabilistic,bool unit)4097 bool cHardwareCPU::DoCollect(cAvidaContext& ctx, bool env_remove, bool internal_add, bool probabilistic, bool unit)
4098 {
4099   int spec_id;
4100 
4101   int bin_used = FindModifiedResource(ctx, spec_id);
4102   if (bin_used < 0) { return false; }  // collection failed, there's nothing to collect
4103 
4104   // Add this specification
4105   m_organism->IncCollectSpecCount(spec_id);
4106 
4107   return DoActualCollect(ctx, bin_used, env_remove, internal_add, probabilistic, unit);
4108 }
4109 
DoActualCollect(cAvidaContext & ctx,int bin_used,bool env_remove,bool internal_add,bool probabilistic,bool unit)4110 bool cHardwareCPU::DoActualCollect(cAvidaContext& ctx, int bin_used, bool env_remove, bool internal_add, bool probabilistic, bool unit)
4111 {
4112   // Set up res_change and max total
4113   const tArray<double> res_count = m_organism->GetOrgInterface().GetResources(ctx);
4114   tArray<double> res_change(res_count.GetSize());
4115   res_change.SetAll(0.0);
4116   double total = m_organism->GetRBinsTotal();
4117   double max = m_world->GetConfig().MAX_TOTAL_STORED.Get();
4118 
4119 	/* First, if collection is probabilistic, check to see if it succeeds.
4120    *
4121    * If so, remove resource(s) from environment if env_remove is set;
4122    * add resource(s) to internal resource bins if internal_add is set
4123    * (and this would not fill the bin beyond max).
4124    */
4125   if (probabilistic) {
4126     double success_chance = res_count[bin_used] / double(m_world->GetConfig().COLLECT_PROB_DIVISOR.Get());
4127     if (success_chance < ctx.GetRandom().GetDouble()) {
4128       return false;
4129     }  // we define not collecting as failure
4130   }
4131 
4132   // Collect a unit (if possible) or some ABSORB_RESOURCE_FRACTION
4133   if (unit) {
4134     if (res_count[bin_used] >= 1.0) {
4135       res_change[bin_used] = -1.0;
4136     }
4137     else {
4138       return false;
4139     }  // failure: not enough to collect
4140   }
4141   else {
4142     res_change[bin_used] = -1 * (res_count[bin_used] * m_world->GetConfig().ABSORB_RESOURCE_FRACTION.Get());
4143   }
4144 
4145   if (internal_add && (max < 0 || (total + -1 * res_change[bin_used]) <= max)) {
4146     m_organism->AddToRBin(bin_used, -1 * res_change[bin_used]);
4147   }
4148 
4149   if (!env_remove || (max >= 0 && (total + -1 * res_change[bin_used]) > max)) {
4150     res_change[bin_used] = 0.0;
4151   }
4152 
4153   // Update resource counts to reflect res_change
4154   m_organism->GetOrgInterface().UpdateResources(ctx, res_change);
4155   return true;
4156 }
4157 
4158 /* Takes resource(s) from the environment and adds them to the internal resource
4159  * bins of the organism.
4160  */
Inst_Collect(cAvidaContext & ctx)4161 bool cHardwareCPU::Inst_Collect(cAvidaContext& ctx)
4162 {
4163   return DoCollect(ctx, true, true, false, false);
4164 }
4165 
4166 /* Like Inst_Collect, but the collected resources are not removed from the
4167  * environment.
4168  */
Inst_CollectNoEnvRemove(cAvidaContext & ctx)4169 bool cHardwareCPU::Inst_CollectNoEnvRemove(cAvidaContext& ctx)
4170 {
4171   return DoCollect(ctx, false, true, false, false);
4172 }
4173 
4174 /* Collects resource from the environment but does not add it to the organism,
4175  * effectively destroying it.
4176  */
Inst_Destroy(cAvidaContext & ctx)4177 bool cHardwareCPU::Inst_Destroy(cAvidaContext& ctx)
4178 {
4179   return DoCollect(ctx, true, false, false, false);
4180 }
4181 
4182 /* A no-op, nop-modified in the same way as the "collect" instructions:
4183  * Does not remove resource from environment, does not add resource to organism */
Inst_NopCollect(cAvidaContext & ctx)4184 bool cHardwareCPU::Inst_NopCollect(cAvidaContext& ctx)
4185 {
4186   return DoCollect(ctx, false, false, false, false);
4187 }
4188 
4189 /* Collects one unit of resource from the environment and adds it to the internal
4190  * resource bins of the organism.  The probability of the instruction succeeding
4191  * is given by the level of that resource divided by the COLLECT_PROB_DIVISOR
4192  * config option.
4193  */
Inst_CollectUnitProbabilistic(cAvidaContext & ctx)4194 bool cHardwareCPU::Inst_CollectUnitProbabilistic(cAvidaContext& ctx)
4195 {
4196   return DoCollect(ctx, true, true, true, true);
4197 }
4198 
4199 /* Takes the resource specified by the COLLECT_RESOURCE_SPECIFIC config option
4200  * from the environment and adds it to the internal resource bins of the organism.
4201  */
Inst_CollectSpecific(cAvidaContext & ctx)4202 bool cHardwareCPU::Inst_CollectSpecific(cAvidaContext& ctx)
4203 {
4204   const int resource = m_world->GetConfig().COLLECT_SPECIFIC_RESOURCE.Get();
4205   double res_before = m_organism->GetRBin(resource);
4206   bool success = DoActualCollect(ctx, resource, true, true, false, false);
4207   double res_after = m_organism->GetRBin(resource);
4208   GetRegister(FindModifiedRegister(REG_BX)) = (int)(res_after - res_before);
4209   return success;
4210 }
4211 
4212 /*Donates resources to the a neighboring cell */
Inst_DonateSpecific(cAvidaContext & ctx)4213 bool cHardwareCPU::Inst_DonateSpecific(cAvidaContext& ctx)
4214 {
4215   if(!m_organism->IsNeighborCellOccupied())return false;
4216   cOrganism* target = NULL;
4217   target = m_organism->GetOrgInterface().GetNeighbor();
4218   const int resource = m_world->GetConfig().COLLECT_SPECIFIC_RESOURCE.Get();
4219   if (m_world->GetConfig().USE_RESOURCE_BINS.Get()){
4220     double res_before = m_organism->GetRBin(resource);
4221     int kin = 0;
4222     if (res_before >= 1)
4223     {
4224       target->AddToRBin (resource, 1);
4225       cBioGroup* bg = m_organism->GetBioGroup("genotype");
4226       if (bg) {
4227         cSexualAncestry* sa = bg->GetData<cSexualAncestry>();
4228         if (!sa) {
4229           sa = new cSexualAncestry(bg);
4230           bg->AttachData(sa);
4231         }
4232         cBioGroup* nbg = target->GetBioGroup("genotype");
4233         assert(nbg);
4234         kin = sa->GetPhyloDistance(nbg);
4235       }
4236       m_organism->GetPhenotype().IncDonates();
4237       m_organism->GetOrgInterface().PushDonateSpecInstExe(ctx, target, kin);
4238       return true;
4239     }
4240   }
4241   return false;
4242 }
4243 
Inst_CheckFacedKin(cAvidaContext & ctx)4244 bool cHardwareCPU::Inst_CheckFacedKin(cAvidaContext& ctx)
4245 {
4246   assert(m_organism != 0);
4247 
4248   if (!m_organism->IsNeighborCellOccupied()) return false;
4249   cOrganism* neighbor =m_organism->GetOrgInterface().GetNeighbor();
4250 
4251   if (neighbor->IsDead())  return false;
4252 
4253   // If there is no valid max genetic distance, go out to cousins.
4254   int gen_dist = GetRegister(FindModifiedRegister(REG_BX));
4255   if (gen_dist > 4 || gen_dist < 0) gen_dist = 4;
4256 
4257   bool is_kin = false;
4258 
4259   cBioGroup* bg = m_organism->GetBioGroup("genotype");
4260   if (!bg) return false;
4261   cSexualAncestry* sa = bg->GetData<cSexualAncestry>();
4262   if (!sa) {
4263     sa = new cSexualAncestry(bg);
4264     bg->AttachData(sa);
4265   }
4266 
4267   cBioGroup* nbg = neighbor->GetBioGroup("genotype");
4268   assert(nbg);
4269   if (sa->GetPhyloDistance(nbg) <= gen_dist) is_kin = true;
4270 
4271   GetRegister(FindModifiedRegister(REG_BX))= gen_dist;
4272   const int out_reg = FindModifiedNextRegister(REG_BX);
4273   GetRegister(out_reg)= (int) is_kin;
4274   return true;
4275 }
4276 
Inst_CheckFacedBeggar(cAvidaContext & ctx)4277 bool cHardwareCPU::Inst_CheckFacedBeggar(cAvidaContext& ctx)
4278 {
4279   assert(m_organism != 0);
4280 
4281   if (!m_organism->IsNeighborCellOccupied()) return false;
4282   cOrganism* neighbor =m_organism->GetOrgInterface().GetNeighbor();
4283 
4284   if (neighbor->IsDead())  return false;
4285 
4286   bool faced_is_beggar = neighbor->IsBeggar();
4287 
4288   const int out_reg = FindModifiedNextRegister(REG_BX);
4289   GetRegister(out_reg) = (int) faced_is_beggar;
4290   return true;
4291 }
4292 
Inst_IfFacedKin(cAvidaContext & ctx)4293 bool cHardwareCPU::Inst_IfFacedKin(cAvidaContext& ctx)
4294 {
4295   assert(m_organism != 0);
4296 
4297   if (!m_organism->IsNeighborCellOccupied()) return false;
4298   cOrganism* neighbor = m_organism->GetOrgInterface().GetNeighbor();
4299 
4300   if (neighbor->IsDead()) return false;
4301 
4302   // default to sibs, grandchild, grandparent
4303   int gen_dist = 2;
4304   if (m_inst_set->IsNop(getIP().GetNextInst())) {
4305     gen_dist = GetRegister(FindModifiedRegister(REG_BX));
4306     // Cousins if high
4307     if (gen_dist > 4) gen_dist = 4;
4308     // Parent/child if low
4309     else if (gen_dist < 1) gen_dist = 1;
4310   }
4311 
4312   bool is_kin = false;
4313 
4314   cBioGroup* bg = m_organism->GetBioGroup("genotype");
4315   if (!bg) return false;
4316   cSexualAncestry* sa = bg->GetData<cSexualAncestry>();
4317   if (!sa) {
4318     sa = new cSexualAncestry(bg);
4319     bg->AttachData(sa);
4320   }
4321 
4322   cBioGroup* nbg = neighbor->GetBioGroup("genotype");
4323   assert(nbg);
4324   if (sa->GetPhyloDistance(nbg) <= gen_dist) is_kin = true;
4325 
4326   if (is_kin) getIP().Advance();
4327   return true;
4328 }
4329 
Inst_IfFacedBeggar(cAvidaContext & ctx)4330 bool cHardwareCPU::Inst_IfFacedBeggar(cAvidaContext& ctx)
4331 {
4332   assert(m_organism != 0);
4333 
4334   if (!m_organism->IsNeighborCellOccupied()) return false;
4335   cOrganism* neighbor =m_organism->GetOrgInterface().GetNeighbor();
4336 
4337   if (neighbor->IsDead())  return false;
4338 
4339   bool is_beggar = neighbor->IsBeggar();
4340 
4341   if (is_beggar) getIP().Advance();
4342   return true;
4343 }
4344 
Inst_IfFacedBeggarAndNeedResource(cAvidaContext & ctx)4345 bool cHardwareCPU::Inst_IfFacedBeggarAndNeedResource(cAvidaContext& ctx)
4346 {
4347   assert(m_organism != 0);
4348 
4349   if (!m_organism->IsNeighborCellOccupied()) return false;
4350   cOrganism* neighbor =m_organism->GetOrgInterface().GetNeighbor();
4351 
4352   if (neighbor->IsDead())  return false;
4353 
4354   bool is_beggar = neighbor->IsBeggar();
4355   const int resource = m_world->GetConfig().COLLECT_SPECIFIC_RESOURCE.Get();
4356   bool needs_resource = (neighbor->GetRBin(resource)<1);
4357   if (is_beggar && needs_resource) getIP().Advance();
4358   return true;
4359 }
4360 
Inst_IfFacedBeggarAndKin(cAvidaContext & ctx)4361 bool cHardwareCPU::Inst_IfFacedBeggarAndKin(cAvidaContext& ctx)
4362 {
4363   assert(m_organism != 0);
4364 
4365   if (!m_organism->IsNeighborCellOccupied()) return false;
4366   cOrganism* neighbor = m_organism->GetOrgInterface().GetNeighbor();
4367 
4368   if (neighbor->IsDead()) return false;
4369 
4370   //check beg flag
4371   bool is_beggar = neighbor->IsBeggar();
4372 
4373   // default to sibs, grandchild, grandparent
4374   int gen_dist = 2;
4375   if (m_inst_set->IsNop(getIP().GetNextInst())) {
4376     gen_dist = GetRegister(FindModifiedRegister(REG_BX));
4377     // Cousins if high
4378     if (gen_dist > 4) gen_dist = 4;
4379       // Parent/child if low
4380       else if (gen_dist < 1) gen_dist = 1;
4381         }
4382 
4383   bool is_kin = false;
4384 
4385   cBioGroup* bg = m_organism->GetBioGroup("genotype");
4386   if (!bg) return false;
4387   cSexualAncestry* sa = bg->GetData<cSexualAncestry>();
4388   if (!sa) {
4389     sa = new cSexualAncestry(bg);
4390     bg->AttachData(sa);
4391   }
4392 
4393   cBioGroup* nbg = neighbor->GetBioGroup("genotype");
4394   assert(nbg);
4395   if (sa->GetPhyloDistance(nbg) <= gen_dist) is_kin = true;
4396 
4397   if (is_kin && is_beggar) getIP().Advance();
4398   return true;
4399 }
Inst_IfFacedKinAndNeedResource(cAvidaContext & ctx)4400 bool cHardwareCPU::Inst_IfFacedKinAndNeedResource(cAvidaContext& ctx)
4401 {
4402   assert(m_organism != 0);
4403 
4404   if (!m_organism->IsNeighborCellOccupied()) return false;
4405   cOrganism* neighbor = m_organism->GetOrgInterface().GetNeighbor();
4406 
4407   if (neighbor->IsDead()) return false;
4408 
4409   //'needs' resource
4410   const int resource = m_world->GetConfig().COLLECT_SPECIFIC_RESOURCE.Get();
4411   bool needs_resource = (neighbor->GetRBin(resource)<1);
4412 
4413   // default to sibs, grandchild, grandparent
4414   int gen_dist = 2;
4415   if (m_inst_set->IsNop(getIP().GetNextInst())) {
4416     gen_dist = GetRegister(FindModifiedRegister(REG_BX));
4417     // Cousins if high
4418     if (gen_dist > 4) gen_dist = 4;
4419     // Parent/child if low
4420     else if (gen_dist < 1) gen_dist = 1;
4421   }
4422 
4423   bool is_kin = false;
4424 
4425   cBioGroup* bg = m_organism->GetBioGroup("genotype");
4426   if (!bg) return false;
4427   cSexualAncestry* sa = bg->GetData<cSexualAncestry>();
4428   if (!sa) {
4429     sa = new cSexualAncestry(bg);
4430     bg->AttachData(sa);
4431   }
4432 
4433   cBioGroup* nbg = neighbor->GetBioGroup("genotype");
4434   assert(nbg);
4435   if (sa->GetPhyloDistance(nbg) <= gen_dist) is_kin = true;
4436 
4437   if (is_kin && needs_resource) getIP().Advance();
4438   return true;
4439 
4440 }
4441 
Inst_IfFacedNeedResource(cAvidaContext & ctx)4442 bool cHardwareCPU::Inst_IfFacedNeedResource(cAvidaContext& ctx)
4443 {
4444   assert(m_organism != 0);
4445 
4446   if (!m_organism->IsNeighborCellOccupied()) return false;
4447   cOrganism* neighbor = m_organism->GetOrgInterface().GetNeighbor();
4448 
4449   if (neighbor->IsDead()) return false;
4450 
4451   //'needs' resource
4452   const int resource = m_world->GetConfig().COLLECT_SPECIFIC_RESOURCE.Get();
4453   bool needs_resource = (neighbor->GetRBin(resource)<1);
4454 
4455   if (needs_resource) getIP().Advance();
4456   return true;
4457 
4458 }
4459 
Inst_IfFacedKinAndBeggarAndNeedResource(cAvidaContext & ctx)4460 bool cHardwareCPU::Inst_IfFacedKinAndBeggarAndNeedResource(cAvidaContext& ctx)
4461 {
4462   assert(m_organism != 0);
4463 
4464   if (!m_organism->IsNeighborCellOccupied()) return false;
4465   cOrganism* neighbor = m_organism->GetOrgInterface().GetNeighbor();
4466 
4467   if (neighbor->IsDead()) return false;
4468 
4469   //check beg flag
4470   bool is_beggar = neighbor->IsBeggar();
4471 
4472   //'needs' resource
4473   const int resource = m_world->GetConfig().COLLECT_SPECIFIC_RESOURCE.Get();
4474   bool needs_resource = (neighbor->GetRBin(resource)<1);
4475 
4476   // default to sibs, grandchild, grandparent
4477   int gen_dist = 2;
4478   if (m_inst_set->IsNop(getIP().GetNextInst())) {
4479     gen_dist = GetRegister(FindModifiedRegister(REG_BX));
4480     // Cousins if high
4481     if (gen_dist > 4) gen_dist = 4;
4482     // Parent/child if low
4483     else if (gen_dist < 1) gen_dist = 1;
4484   }
4485 
4486   bool is_kin = false;
4487 
4488   cBioGroup* bg = m_organism->GetBioGroup("genotype");
4489   if (!bg) return false;
4490   cSexualAncestry* sa = bg->GetData<cSexualAncestry>();
4491   if (!sa) {
4492     sa = new cSexualAncestry(bg);
4493     bg->AttachData(sa);
4494   }
4495 
4496   cBioGroup* nbg = neighbor->GetBioGroup("genotype");
4497   assert(nbg);
4498   if (sa->GetPhyloDistance(nbg) <= gen_dist) is_kin = true;
4499 
4500   if (is_kin && needs_resource && is_beggar) getIP().Advance();
4501   return true;
4502 }
4503 
Inst_IfFacedKinAndBeggarAndNeedResourceThenDonate(cAvidaContext & ctx)4504 bool cHardwareCPU::Inst_IfFacedKinAndBeggarAndNeedResourceThenDonate(cAvidaContext& ctx)
4505 {
4506   assert(m_organism != 0);
4507 
4508   if (!m_organism->IsNeighborCellOccupied()) return false;
4509   cOrganism* neighbor = m_organism->GetOrgInterface().GetNeighbor();
4510 
4511   if (neighbor->IsDead()) return false;
4512 
4513   //check beg flag
4514   bool is_beggar = neighbor->IsBeggar();
4515 
4516   //'needs' resource
4517   const int resource = m_world->GetConfig().COLLECT_SPECIFIC_RESOURCE.Get();
4518   bool needs_resource = (neighbor->GetRBin(resource)<1);
4519 
4520   // default to sibs, grandchild, grandparent
4521   int gen_dist = 2;
4522   if (m_inst_set->IsNop(getIP().GetNextInst())) {
4523     gen_dist = GetRegister(FindModifiedRegister(REG_BX));
4524     // Cousins if high
4525     if (gen_dist > 4) gen_dist = 4;
4526     // Parent/child if low
4527     else if (gen_dist < 1) gen_dist = 1;
4528   }
4529 
4530   bool is_kin = false;
4531 
4532   cBioGroup* bg = m_organism->GetBioGroup("genotype");
4533   if (!bg) return false;
4534   cSexualAncestry* sa = bg->GetData<cSexualAncestry>();
4535   if (!sa) {
4536     sa = new cSexualAncestry(bg);
4537     bg->AttachData(sa);
4538   }
4539 
4540   cBioGroup* nbg = neighbor->GetBioGroup("genotype");
4541   assert(nbg);
4542   if (sa->GetPhyloDistance(nbg) <= gen_dist) is_kin = true;
4543 
4544   if (is_kin && needs_resource && is_beggar)
4545   {
4546     cOrganism* target = NULL;
4547     target = m_organism->GetOrgInterface().GetNeighbor();
4548     if (m_world->GetConfig().USE_RESOURCE_BINS.Get()){
4549       double res_before = m_organism->GetRBin(resource);
4550       int kin = 0;
4551       if (res_before >= 1)
4552       {
4553         target->AddToRBin (resource, 1);
4554 
4555         cBioGroup* bg = m_organism->GetBioGroup("genotype");
4556         if (bg) {
4557           cSexualAncestry* sa = bg->GetData<cSexualAncestry>();
4558           if (!sa) {
4559             sa = new cSexualAncestry(bg);
4560             bg->AttachData(sa);
4561           }
4562           cBioGroup* nbg = target->GetBioGroup("genotype");
4563           assert(nbg);
4564           kin = sa->GetPhyloDistance(nbg);
4565         }
4566         m_organism->GetPhenotype().IncDonates();
4567         m_organism->GetOrgInterface().PushDonateSpecInstExe(ctx, target, kin);
4568         return true;
4569       }
4570     }
4571   }
4572   return false;
4573 }
4574 
Inst_IfFacedBeggarANdNeedsResourceThenDonate(cAvidaContext & ctx)4575 bool cHardwareCPU::Inst_IfFacedBeggarANdNeedsResourceThenDonate(cAvidaContext& ctx)
4576 {
4577   assert(m_organism != 0);
4578 
4579   if (!m_organism->IsNeighborCellOccupied()) return false;
4580   cOrganism* neighbor =m_organism->GetOrgInterface().GetNeighbor();
4581 
4582   if (neighbor->IsDead())  return false;
4583 
4584   bool is_beggar = neighbor->IsBeggar();
4585   const int resource = m_world->GetConfig().COLLECT_SPECIFIC_RESOURCE.Get();
4586   bool needs_resource = (neighbor->GetRBin(resource)<1);
4587   if (is_beggar && needs_resource)
4588   {
4589     cOrganism* target = NULL;
4590     target = m_organism->GetOrgInterface().GetNeighbor();
4591     if (m_world->GetConfig().USE_RESOURCE_BINS.Get()){
4592       double res_before = m_organism->GetRBin(resource);
4593       int kin = 0;
4594       if (res_before >= 1)
4595       {
4596         target->AddToRBin (resource, 1);
4597 
4598         cBioGroup* bg = m_organism->GetBioGroup("genotype");
4599         if (bg) {
4600           cSexualAncestry* sa = bg->GetData<cSexualAncestry>();
4601           if (!sa) {
4602             sa = new cSexualAncestry(bg);
4603             bg->AttachData(sa);
4604           }
4605           cBioGroup* nbg = target->GetBioGroup("genotype");
4606           assert(nbg);
4607           kin = sa->GetPhyloDistance(nbg);
4608         }
4609         m_organism->GetPhenotype().IncDonates();
4610         m_organism->GetOrgInterface().PushDonateSpecInstExe(ctx, target, kin);
4611         return true;
4612       }
4613     }
4614     return false;
4615   }
4616 
4617 }
4618 
Inst_FailIfEmpty(cAvidaContext & ctx)4619 bool cHardwareCPU::Inst_FailIfEmpty(cAvidaContext& ctx)
4620 {
4621   const int resource = m_world->GetConfig().COLLECT_SPECIFIC_RESOURCE.Get();
4622   if (m_world->GetConfig().USE_RESOURCE_BINS.Get()){
4623     double res_amt = m_organism->GetRBin(resource);
4624     if (res_amt < 1)
4625     {
4626       return true;
4627     }
4628   }
4629   return false;
4630 }
4631 
Inst_SetBeggar(cAvidaContext & ctx)4632 bool cHardwareCPU::Inst_SetBeggar(cAvidaContext& ctx)
4633 {
4634   assert(m_organism != 0);
4635   m_organism->ChangeBeg();
4636   return true;
4637 }
4638 
4639 /*! Sense the level of resources in this organism's cell, and if all of the
4640  resources present are above the min level for that resource, execute the following
4641  intruction.  Otherwise, skip the following instruction.
4642  */
Inst_IfResources(cAvidaContext & ctx)4643 bool cHardwareCPU::Inst_IfResources(cAvidaContext& ctx)
4644 {
4645   // These are the current levels of resources at this cell:
4646   const tArray<double> resources = m_organism->GetOrgInterface().GetResources(ctx) +
4647   m_organism->GetOrgInterface().GetDemeResources(m_organism->GetOrgInterface().GetDemeID(), ctx);
4648 
4649   // Now we loop through the different reactions, checking to see if their
4650   // required resources are below what's available.  If so, we skip ahead an
4651   // instruction and return.
4652   const cReactionLib& rxlib = m_world->GetEnvironment().GetReactionLib();
4653   for (int i=0; i<rxlib.GetSize(); ++i) {
4654     cReaction* rx = rxlib.GetReaction(i);
4655     tLWConstListIterator<cReactionProcess> processes(rx->GetProcesses());
4656     while (!processes.AtEnd()) {
4657       const cReactionProcess* proc = processes.Next();
4658       cResource* res = proc->GetResource(); // Infinite resource == 0.
4659       if ((res != 0) && (resources[res->GetID()] < proc->GetMinNumber())) {
4660         getIP().Advance();
4661         return true;
4662       }
4663     }
4664   }
4665   return true;
4666 }
4667 
DoDonate(cOrganism * to_org)4668 void cHardwareCPU::DoDonate(cOrganism* to_org)
4669 {
4670   assert(to_org != NULL);
4671 
4672   const double merit_given = m_world->GetConfig().MERIT_GIVEN.Get();
4673   const double merit_received = m_world->GetConfig().MERIT_RECEIVED.Get();
4674 
4675   double cur_merit = m_organism->GetPhenotype().GetMerit().GetDouble();
4676   cur_merit -= merit_given;
4677   if (cur_merit < 0) cur_merit=0;
4678 
4679   // Plug the current merit back into this organism and notify the scheduler.
4680   m_organism->UpdateMerit(cur_merit);
4681   m_organism->GetPhenotype().SetIsEnergyDonor();
4682 
4683   // Update the merit of the organism being donated to...
4684   double other_merit = to_org->GetPhenotype().GetMerit().GetDouble();
4685   other_merit += merit_received;
4686   to_org->UpdateMerit(other_merit);
4687   to_org->GetPhenotype().SetIsEnergyReceiver();
4688 
4689 }
4690 
DoEnergyDonate(cOrganism * to_org)4691 void cHardwareCPU::DoEnergyDonate(cOrganism* to_org)
4692 {
4693   assert(to_org != NULL);
4694 
4695   const double frac_energy_given = m_organism->GetFracEnergyDonating();
4696 
4697   cPhenotype& phenotype = m_organism->GetPhenotype();
4698 
4699   double cur_energy = phenotype.GetStoredEnergy();
4700   double energy_given = cur_energy * frac_energy_given;
4701 
4702   //update energy store and merit of donor
4703   phenotype.ReduceEnergy(energy_given);
4704   phenotype.IncreaseEnergyDonated(energy_given);
4705   double senderMerit = phenotype.ConvertEnergyToMerit(phenotype.GetStoredEnergy()  * phenotype.GetEnergyUsageRatio());
4706   m_organism->UpdateMerit(senderMerit);
4707   phenotype.SetIsEnergyDonor();
4708 
4709   // update energy store and merit of donee
4710   to_org->GetPhenotype().ReduceEnergy(-1.0*energy_given);
4711   to_org->GetPhenotype().IncreaseEnergyReceived(energy_given);
4712   double receiverMerit = to_org->GetPhenotype().ConvertEnergyToMerit(to_org->GetPhenotype().GetStoredEnergy() * to_org->GetPhenotype().GetEnergyUsageRatio());
4713   to_org->UpdateMerit(receiverMerit);
4714   to_org->GetPhenotype().SetIsEnergyReceiver();
4715 }
4716 
4717 
DoEnergyDonatePercent(cOrganism * to_org,const double frac_energy_given)4718 void cHardwareCPU::DoEnergyDonatePercent(cOrganism* to_org, const double frac_energy_given)
4719 {
4720   assert(to_org != NULL);
4721   assert(frac_energy_given >= 0);
4722   assert(frac_energy_given <= 1);
4723 
4724   DoEnergyDonateAmount(to_org, m_organism->GetPhenotype().GetStoredEnergy() * frac_energy_given);
4725 
4726 } //End DoEnergyDonatePercent()
4727 
4728 
4729 // The difference between this version and the previous is that this one allows energy to be placed
4730 // into the recipient's incoming energy buffer and not be applied immediately.  Also, some of the
4731 // energy may be lost in transfer
DoEnergyDonateAmount(cOrganism * to_org,const double amount)4732 void cHardwareCPU::DoEnergyDonateAmount(cOrganism* to_org, const double amount)
4733 {
4734   double losspct = m_world->GetConfig().RESOURCE_SHARING_LOSS.Get();
4735 
4736   assert(to_org != NULL);
4737   assert(amount >= 0);
4738   assert(losspct >= 0);
4739   assert(losspct <= 1);
4740 
4741   cPhenotype& phenotype = m_organism->GetPhenotype();
4742 
4743   const int update_metabolic = m_world->GetConfig().ENERGY_SHARING_UPDATE_METABOLIC.Get();
4744   double energy_given = min(phenotype.GetStoredEnergy(), amount);
4745   double energy_received;
4746 
4747   //update energy store and merit of donor
4748   phenotype.ReduceEnergy(energy_given);
4749   phenotype.SetIsEnergyDonor();
4750   phenotype.IncreaseEnergyDonated(energy_given);
4751   phenotype.IncreaseNumEnergyDonations();
4752 
4753   m_organism->GetDeme()->IncreaseEnergyDonated(energy_given);
4754 
4755   if (update_metabolic == 1) {
4756     double senderMerit = phenotype.ConvertEnergyToMerit(phenotype.GetStoredEnergy()  * phenotype.GetEnergyUsageRatio());
4757     m_organism->UpdateMerit(senderMerit);
4758   }
4759 
4760   //apply loss in transfer
4761   energy_received = energy_given * (1 - losspct);
4762 
4763   //place energy into receiver's incoming energy buffer
4764   to_org->GetPhenotype().ReceiveDonatedEnergy(energy_received);
4765   to_org->GetDeme()->IncreaseEnergyReceived(energy_received);   // Harder for phenotype to get the deme, so it's done here
4766 
4767   //if we are using the push energy method, pass the new energy into the receiver's energy store and recalculate merit
4768   if (m_world->GetConfig().ENERGY_SHARING_METHOD.Get() == 1) {
4769     to_org->GetPhenotype().ApplyDonatedEnergy();
4770 
4771     if (update_metabolic == 1) {
4772       double receiverMerit = to_org->GetPhenotype().ConvertEnergyToMerit(to_org->GetPhenotype().GetStoredEnergy() * to_org->GetPhenotype().GetEnergyUsageRatio());
4773       to_org->UpdateMerit(receiverMerit);
4774     }
4775   }
4776 
4777 
4778   if (m_world->GetConfig().LOG_ENERGY_SHARING.Get() == 1) {
4779     cString tmpfilename = cStringUtil::Stringf("energy_sharing_log.dat");
4780     cDataFile& df = m_world->GetDataFile(tmpfilename);
4781 
4782     cString UpdateStr = cStringUtil::Stringf("%d,%d,%d,%f,%f,%d,%f,%f",
4783                                              m_world->GetStats().GetUpdate(),
4784                                              m_world->GetConfig().ENERGY_SHARING_METHOD.Get(),
4785                                              m_organism->GetID(),
4786                                              energy_given,
4787                                              phenotype.GetStoredEnergy(),
4788                                              to_org->GetID(),
4789                                              energy_received,
4790                                              to_org->GetPhenotype().GetStoredEnergy());
4791     df.WriteRaw(UpdateStr);
4792 
4793   }
4794 
4795 } //End DoEnergyDonateAmount()
4796 
4797 
Inst_DonateFacing(cAvidaContext & ctx)4798 bool cHardwareCPU::Inst_DonateFacing(cAvidaContext& ctx)
4799 {
4800   if (m_organism->GetPhenotype().GetCurNumDonates() > m_world->GetConfig().MAX_DONATES.Get()) {
4801     return false;
4802   }
4803   m_organism->GetPhenotype().IncDonates();
4804   m_organism->GetPhenotype().SetIsDonorRand();
4805 
4806   // Get faced neighbor
4807   cOrganism * neighbor = m_organism->GetNeighbor();
4808 
4809   // Donate only if we have found a neighbor.
4810   if (neighbor != NULL) {
4811     DoEnergyDonate(neighbor);
4812 
4813     neighbor->GetPhenotype().SetIsReceiver();
4814   }
4815   return true;
4816 }
4817 
Inst_DonateRandom(cAvidaContext & ctx)4818 bool cHardwareCPU::Inst_DonateRandom(cAvidaContext& ctx)
4819 {
4820 
4821   if (m_organism->GetPhenotype().GetCurNumDonates() > m_world->GetConfig().MAX_DONATES.Get()) {
4822     return false;
4823   }
4824 
4825   m_organism->GetPhenotype().IncDonates();
4826   m_organism->GetPhenotype().SetIsDonorRand();
4827 
4828   // Turn to a random neighbor, get it, and turn back...
4829   int neighbor_id = ctx.GetRandom().GetInt(m_organism->GetNeighborhoodSize());
4830   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(1);
4831   cOrganism* neighbor = m_organism->GetNeighbor();
4832   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(-1);
4833 
4834   // Donate only if we have found a neighbor.
4835   if (neighbor != NULL) {
4836     DoDonate(neighbor);
4837 
4838     neighbor->GetPhenotype().SetIsReceiverRand();
4839   }
4840 
4841   return true;
4842 
4843 }
4844 
4845 
Inst_DonateKin(cAvidaContext & ctx)4846 bool cHardwareCPU::Inst_DonateKin(cAvidaContext& ctx)
4847 {
4848   if (m_organism->GetPhenotype().GetCurNumDonates() > m_world->GetConfig().MAX_DONATES.Get()) {
4849     return false;
4850   }
4851 
4852   m_organism->GetPhenotype().IncDonates();
4853   m_organism->GetPhenotype().SetIsDonorKin();
4854 
4855 
4856   // Find the target as the first Kin found in the neighborhood.
4857   const int num_neighbors = m_organism->GetNeighborhoodSize();
4858 
4859   // Turn to face a random neighbor
4860   int neighbor_id = ctx.GetRandom().GetInt(num_neighbors);
4861   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(1);
4862   cOrganism * neighbor = m_organism->GetNeighbor();
4863 
4864   // If there is no max distance, just take the random neighbor we're facing.
4865   const int max_dist = m_world->GetConfig().MAX_DONATE_KIN_DIST.Get();
4866   if (max_dist != -1) {
4867     int max_id = neighbor_id + num_neighbors;
4868     bool found = false;
4869     cBioGroup* bg = m_organism->GetBioGroup("genotype");
4870     if (!bg) return false;
4871     cSexualAncestry* sa = bg->GetData<cSexualAncestry>();
4872     if (!sa) {
4873       sa = new cSexualAncestry(bg);
4874       bg->AttachData(sa);
4875     }
4876 
4877     while (neighbor_id < max_id) {
4878       neighbor = m_organism->GetNeighbor();
4879       if (neighbor != NULL) {
4880         cBioGroup* nbg = neighbor->GetBioGroup("genotype");
4881         assert(nbg);
4882         if (sa->GetPhyloDistance(nbg) <= max_dist) {
4883           found = true;
4884           break;
4885         }
4886       }
4887       m_organism->Rotate(1);
4888       neighbor_id++;
4889     }
4890     if (found == false) neighbor = NULL;
4891   }
4892 
4893   // Put the facing back where it was.
4894   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(-1);
4895 
4896   // Donate only if we have found a close enough relative...
4897   if (neighbor != NULL){
4898     DoDonate(neighbor);
4899     neighbor->GetPhenotype().SetIsReceiverKin();
4900   }
4901   return true;
4902 }
4903 
Inst_DonateEditDist(cAvidaContext & ctx)4904 bool cHardwareCPU::Inst_DonateEditDist(cAvidaContext& ctx)
4905 {
4906   if (m_organism->GetPhenotype().GetCurNumDonates() > m_world->GetConfig().MAX_DONATES.Get()) {
4907     return false;
4908   }
4909 
4910   m_organism->GetPhenotype().IncDonates();
4911   m_organism->GetPhenotype().SetIsDonorEdit();
4912 
4913   // Find the target as the first Kin found in the neighborhood.
4914   const int num_neighbors = m_organism->GetNeighborhoodSize();
4915 
4916   // Turn to face a random neighbor
4917   int neighbor_id = ctx.GetRandom().GetInt(num_neighbors);
4918   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(1);
4919   cOrganism* neighbor = m_organism->GetNeighbor();
4920 
4921   // If there is no max edit distance, take the random neighbor we're facing.
4922   const int max_dist = m_world->GetConfig().MAX_DONATE_EDIT_DIST.Get();
4923   if (max_dist != -1) {
4924     int max_id = neighbor_id + num_neighbors;
4925     bool found = false;
4926     while (neighbor_id < max_id) {
4927       neighbor = m_organism->GetNeighbor();
4928       int edit_dist = max_dist + 1;
4929       if (neighbor != NULL) {
4930         edit_dist = Sequence::FindEditDistance(m_organism->GetGenome().GetSequence(),
4931                                                 neighbor->GetGenome().GetSequence());
4932       }
4933       if (edit_dist <= max_dist) {
4934         found = true;
4935 
4936 	// Code to track the edit distance between edt donors and recipients
4937 	const int edit_dist = Sequence::FindEditDistance(m_organism->GetGenome().GetSequence(),
4938                                                           neighbor->GetGenome().GetSequence());
4939 
4940 	/*static ofstream edit_file("edit_dists.dat");*/
4941 	static int num_edit_donates = 0;
4942 	static int num_edit_donates_15_dist = 0;
4943 	static int tot_dist_edit_donate = 0;
4944 
4945 	num_edit_donates++;
4946 	if (edit_dist > 15) num_edit_donates_15_dist++;
4947 	tot_dist_edit_donate += edit_dist;
4948 
4949 	if (num_edit_donates == 1000) {
4950 	  /*
4951 	    edit_file << num_edit_donates << " "
4952 	    << (double) num_edit_donates_15_dist / (double) num_edit_donates << " "
4953 	    << (double) tot_dist_edit_donate / (double) num_edit_donates << endl;
4954 	  */
4955 
4956 	  num_edit_donates = 0;
4957 	  num_edit_donates_15_dist = 0;
4958 	  tot_dist_edit_donate = 0;
4959 	}
4960 
4961         break;
4962       }
4963       m_organism->Rotate(1);
4964       neighbor_id++;
4965     }
4966     if (found == false) neighbor = NULL;
4967   }
4968 
4969   // Put the facing back where it was.
4970   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(-1);
4971 
4972   // Donate only if we have found a close enough relative...
4973   if (neighbor != NULL){
4974     DoDonate(neighbor);
4975     neighbor->GetPhenotype().SetIsReceiverEdit();
4976   }
4977   return true;
4978 
4979 }
4980 
Inst_DonateGreenBeardGene(cAvidaContext & ctx)4981 bool cHardwareCPU::Inst_DonateGreenBeardGene(cAvidaContext& ctx)
4982 {
4983   //this donates to organisms that have this instruction anywhere
4984   //in their genome (see Dawkins 1976, The Selfish Gene, for
4985   //the history of the theory and the name 'green beard'
4986   cPhenotype & phenotype = m_organism->GetPhenotype();
4987 
4988   if (m_organism->GetPhenotype().GetCurNumDonates() > m_world->GetConfig().MAX_DONATES.Get()) {
4989     return false;
4990   }
4991 
4992   phenotype.IncDonates();
4993   phenotype.SetIsDonorGbg();
4994 
4995   // Find the target as the first match found in the neighborhood.
4996 
4997   //get the neighborhood size
4998   const int num_neighbors = m_organism->GetNeighborhoodSize();
4999 
5000   // Turn to face a random neighbor
5001   int neighbor_id = ctx.GetRandom().GetInt(num_neighbors);
5002   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(1);
5003   cOrganism * neighbor = m_organism->GetNeighbor();
5004 
5005 
5006   int max_id = neighbor_id + num_neighbors;
5007 
5008   //we have not found a match yet
5009   bool found = false;
5010 
5011   // rotate through orgs in neighborhood
5012   while (neighbor_id < max_id) {
5013     neighbor = m_organism->GetNeighbor();
5014 
5015     //if neighbor exists, do they have the green beard gene?
5016     if (neighbor != NULL) {
5017       const Sequence& neighbor_genome = neighbor->GetGenome().GetSequence();
5018 
5019       // for each instruction in the genome...
5020       for (int i = 0; i < neighbor_genome.GetSize(); i++){
5021 
5022 	// ...see if it is donate-gbg
5023 	if (neighbor_genome[i] == getIP().GetInst()) {
5024 	  found = true;
5025 	  break;
5026 	}
5027 
5028       }
5029     }
5030 
5031     // stop searching through the neighbors if we already found one
5032     if (found == true){
5033       break;
5034     }
5035 
5036     m_organism->Rotate(1);
5037     neighbor_id++;
5038   }
5039 
5040   if (found == false) neighbor = NULL;
5041 
5042   // Put the facing back where it was.
5043   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(-1);
5044 
5045   // Donate only if we have found a close enough relative...
5046   if (neighbor != NULL) {
5047     DoDonate(neighbor);
5048     neighbor->GetPhenotype().SetIsReceiverGbg();
5049   }
5050 
5051   return true;
5052 
5053 }
5054 
5055 /* This instruction donates to other organisms that have at least
5056  as many donate-shaded-greenbeard instructions in their organism
5057  as this organism does. */
Inst_DonateShadedGreenBeard(cAvidaContext & ctx)5058 bool cHardwareCPU::Inst_DonateShadedGreenBeard(cAvidaContext& ctx)
5059 {
5060   cPhenotype & phenotype = m_organism->GetPhenotype();
5061 
5062   // Determine if this m_organism is below the threshold and thus eligible to donate.
5063   if (m_organism->GetPhenotype().GetCurNumDonates() > m_world->GetConfig().MAX_DONATES.Get()) {
5064     return false;
5065   }
5066 
5067   // Identify how many green beard donations the parent of this organism made
5068 
5069   // Identify how many shaded green beard donations this organisms made
5070   // First figure out what number instruction donate-shadedgb is
5071   const int num_inst = m_inst_set->GetSize();
5072   int shade_of_gb = 0;
5073   int neighbor_shade_of_gb = 0;
5074   int inst_number = 0;
5075   for (int i = 0; i < num_inst; i++) {
5076     if ((m_inst_set->GetName(i) == "donate-shadedgb") && (phenotype.GetTestCPUInstCount().GetSize() > 0)) {
5077       shade_of_gb = phenotype.GetTestCPUInstCount()[i];
5078       inst_number = i;
5079     }
5080   }
5081 
5082 
5083   // Update stats.
5084   phenotype.IncDonates();
5085   phenotype.SetIsDonorShadedGb();
5086   phenotype.IncNumShadedGbDonations();
5087 
5088   // Find the target as the first match found in the neighborhood.
5089   //get the neighborhood size
5090   const int num_neighbors = m_organism->GetNeighborhoodSize();
5091 
5092   // Turn to face a random neighbor
5093   // Part of the reason the donates fail so frequently is that this code
5094   // although it randomizes the neighbor, does not take into account whether
5095   // a neigbhor is there or not.
5096   int neighbor_id = ctx.GetRandom().GetInt(num_neighbors);
5097   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(1);
5098   cOrganism * neighbor = m_organism->GetNeighbor();
5099 
5100   int max_id = neighbor_id + num_neighbors;
5101 
5102   //we have not found a match yet
5103   bool found = false;
5104 
5105   // rotate through orgs in neighborhood
5106   while (neighbor_id < max_id) {
5107     neighbor = m_organism->GetNeighbor();
5108     //if neighbor exists, AND if their parent attempted to donate >= shaded of green beard,
5109     if (neighbor != NULL) {
5110 
5111       // Get the neighbor's shade
5112       neighbor_shade_of_gb = 0;
5113       if (neighbor->GetPhenotype().GetTestCPUInstCount().GetSize() > 0) {
5114 	neighbor_shade_of_gb = neighbor->GetPhenotype().GetTestCPUInstCount()[inst_number];
5115       }
5116 
5117       // Changing this line makes shaded gb ONLY donate to organisms with the exact same
5118       // shade (color/number of donations)
5119       //			if (neighbor_shade_of_gb >=  shade_of_gb) {
5120       if (neighbor_shade_of_gb ==  shade_of_gb) {
5121 	// Code to track the edit distance between shaded donors and recipients
5122 	const int edit_dist = Sequence::FindEditDistance(m_organism->GetGenome().GetSequence(),
5123                                                           neighbor->GetGenome().GetSequence());
5124 
5125 	/*static ofstream gb_file("shaded_gb_dists.dat");*/
5126 	static int num_gb_donates = 0;
5127 	static int num_gb_donates_15_dist = 0;
5128 	static int tot_dist_gb_donate = 0;
5129 
5130 	num_gb_donates++;
5131 	if (edit_dist > 15) num_gb_donates_15_dist++;
5132 	tot_dist_gb_donate += edit_dist;
5133 
5134 	if (num_gb_donates == 1000) {
5135 	  /*
5136 	    gb_file << num_gb_donates << " "
5137 	    << (double) num_gb_donates_15_dist / (double) num_gb_donates << " "
5138 	    << (double) tot_dist_gb_donate / (double) num_gb_donates << endl;
5139 	  */
5140 
5141 	  num_gb_donates = 0;
5142 	  num_gb_donates_15_dist = 0;
5143 	  tot_dist_gb_donate = 0;
5144 	}
5145 
5146 	found = true;
5147       }
5148     }
5149 
5150     // stop searching through the neighbors if we already found one
5151     if (found == true){
5152       break;
5153     }
5154 
5155     m_organism->Rotate(1);
5156     neighbor_id++;
5157   }
5158 
5159   if (found == false) neighbor = NULL;
5160 
5161   // Put the facing back where it was.
5162   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(-1);
5163 
5164   // Donate only if we have found a close enough relative...
5165   if (neighbor != NULL) {
5166     DoDonate(neighbor);
5167     neighbor->GetPhenotype().SetIsReceiverShadedGb();
5168   }
5169 
5170   return true;
5171 
5172 }
5173 
5174 
5175 
Inst_DonateTrueGreenBeard(cAvidaContext & ctx)5176 bool cHardwareCPU::Inst_DonateTrueGreenBeard(cAvidaContext& ctx)
5177 {
5178   //this donates to organisms that have this instruction anywhere
5179   //in their genome AND their parents excuted it
5180   //(see Dawkins 1976, The Selfish Gene, for
5181   //the history of the theory and the name 'green beard'
5182   //  cout << "i am about to donate to a green beard" << endl;
5183   cPhenotype & phenotype = m_organism->GetPhenotype();
5184 
5185   if (m_organism->GetPhenotype().GetCurNumDonates() > m_world->GetConfig().MAX_DONATES.Get()) {
5186     return false;
5187   }
5188 
5189   phenotype.IncDonates();
5190   phenotype.SetIsDonorTrueGb();
5191 
5192   // Find the target as the first match found in the neighborhood.
5193 
5194   //get the neighborhood size
5195   const int num_neighbors = m_organism->GetNeighborhoodSize();
5196 
5197   // Get greenbeard instruction number
5198   const int num_inst = m_inst_set->GetSize();
5199   int inst_number = 0;
5200   for (int i = 0; i < num_inst; i++) {
5201     if (m_inst_set->GetName(i) == "donate-tgb") {
5202       inst_number = i;
5203     }
5204   }
5205 
5206   // Turn to face a random neighbor
5207   int neighbor_id = ctx.GetRandom().GetInt(num_neighbors);
5208   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(1);
5209   cOrganism * neighbor = m_organism->GetNeighbor();
5210 
5211   int max_id = neighbor_id + num_neighbors;
5212 
5213   //we have not found a match yet
5214   bool found = false;
5215 
5216   // rotate through orgs in neighborhood
5217   while (neighbor_id < max_id) {
5218     neighbor = m_organism->GetNeighbor();
5219     //if neighbor is a green beard
5220     if (neighbor->GetPhenotype().GetTestCPUInstCount()[inst_number]) {
5221       found = true;
5222     }
5223 
5224     // stop searching through the neighbors if we already found one
5225     if (found == true){
5226       break;
5227     }
5228 
5229     m_organism->Rotate(1);
5230     neighbor_id++;
5231   }
5232 
5233   if (found == false) neighbor = NULL;
5234 
5235   // Put the facing back where it was.
5236   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(-1);
5237 
5238   // Donate only if we have found a close enough relative...
5239   if (neighbor != NULL) {
5240     DoDonate(neighbor);
5241     neighbor->GetPhenotype().SetIsReceiverTrueGb();
5242   }
5243 
5244 
5245   return true;
5246 
5247 }
5248 
Inst_DonateThreshGreenBeard(cAvidaContext & ctx)5249 bool cHardwareCPU::Inst_DonateThreshGreenBeard(cAvidaContext& ctx)
5250 {
5251   //this donates to organisms that have this instruction anywhere
5252   //in their genome AND their parents excuted it >=THRESHOLD number of times
5253   //(see Dawkins 1976, The Selfish Gene, for
5254   //the history of the theory and the name 'green beard'
5255   //  cout << "i am about to donate to a green beard" << endl;
5256   cPhenotype & phenotype = m_organism->GetPhenotype();
5257 
5258   if (m_organism->GetPhenotype().GetCurNumDonates() > m_world->GetConfig().MAX_DONATES.Get()) {
5259     return false;
5260   }
5261 
5262 
5263   phenotype.IncDonates();
5264   phenotype.SetIsDonorThreshGb();
5265   phenotype.IncNumThreshGbDonations();
5266 
5267 
5268   // Identify how many thresh green beard donations this organisms made
5269   // First figure out what number instruction donate-threshgb is
5270   const int num_inst = m_inst_set->GetSize();
5271   int neighbor_thresh_of_gb = 0;
5272   int inst_number = 0;
5273   for (int i = 0; i < num_inst; i++) {
5274     if ((m_inst_set->GetName(i) == "donate-threshgb") && (phenotype.GetTestCPUInstCount().GetSize() > 0)) {
5275       inst_number = i;
5276     }
5277   }
5278 
5279   // Find the target as the first match found in the neighborhood.
5280 
5281   //get the neighborhood size
5282   const int num_neighbors = m_organism->GetNeighborhoodSize();
5283 
5284   // Turn to face a random neighbor
5285   int neighbor_id = ctx.GetRandom().GetInt(num_neighbors);
5286   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(1);
5287   cOrganism * neighbor = m_organism->GetNeighbor();
5288 
5289   int max_id = neighbor_id + num_neighbors;
5290 
5291   //we have not found a match yet
5292   bool found = false;
5293 
5294   // rotate through orgs in neighborhood
5295   while (neighbor_id < max_id) {
5296     neighbor = m_organism->GetNeighbor();
5297     //if neighbor exists, AND if their parent attempted to donate >= threshhold,
5298     if (neighbor != NULL) {
5299 
5300       // Get neighbor threshold
5301       neighbor_thresh_of_gb = 0;
5302       if (neighbor->GetPhenotype().GetTestCPUInstCount().GetSize() > 0) {
5303 	neighbor_thresh_of_gb = neighbor->GetPhenotype().GetTestCPUInstCount()[inst_number];
5304       }
5305 
5306       if (neighbor_thresh_of_gb >= m_world->GetConfig().MIN_GB_DONATE_THRESHOLD.Get() ) {
5307 	const Sequence& neighbor_genome = neighbor->GetGenome().GetSequence();
5308 
5309 	// Code to track the edit distance between tgb donors and recipients
5310 	const int edit_dist = Sequence::FindEditDistance(m_organism->GetGenome().GetSequence(),
5311                                                           neighbor->GetGenome().GetSequence());
5312 
5313 	/*static ofstream tgb_file("thresh_gb_dists.dat");*/
5314 	static int num_tgb_donates = 0;
5315 	static int num_tgb_donates_15_dist = 0;
5316 	static int tot_dist_tgb_donate = 0;
5317 
5318 	num_tgb_donates++;
5319 	if (edit_dist > 15) num_tgb_donates_15_dist++;
5320 	tot_dist_tgb_donate += edit_dist;
5321 
5322 	if (num_tgb_donates == 1000) {
5323 	  /*
5324 	    tgb_file << num_tgb_donates << " "
5325 	    << (double) num_tgb_donates_15_dist / (double) num_tgb_donates << " "
5326 	    << (double) tot_dist_tgb_donate / (double) num_tgb_donates << endl;
5327 	  */
5328 
5329 	  num_tgb_donates = 0;
5330 	  num_tgb_donates_15_dist = 0;
5331 	  tot_dist_tgb_donate = 0;
5332 	}
5333 
5334 	// for each instruction in the genome...
5335 	for (int i=0;i<neighbor_genome.GetSize();i++){
5336 
5337 	  // ...see if it is donate-threshgb, if so, we found a target
5338 	  if (neighbor_genome[i] == getIP().GetInst()) {
5339 	    found = true;
5340 	    break;
5341 	  }
5342 
5343 	}
5344       }
5345     }
5346 
5347     // stop searching through the neighbors if we already found one
5348     if (found == true){
5349       break;
5350     }
5351 
5352     m_organism->Rotate(1);
5353     neighbor_id++;
5354   }
5355 
5356   if (found == false) neighbor = NULL;
5357 
5358   // Put the facing back where it was.
5359   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(-1);
5360 
5361   // Donate only if we have found a close enough relative...
5362   if (neighbor != NULL) {
5363     DoDonate(neighbor);
5364     neighbor->GetPhenotype().SetIsReceiverThreshGb();
5365     // cout << "************ neighbor->GetPhenotype().GetNumThreshGbDonationsLast() is " << neighbor->GetPhenotype().GetNumThreshGbDonationsLast() << endl;
5366 
5367   }
5368 
5369   return true;
5370 }
5371 
5372 
Inst_DonateQuantaThreshGreenBeard(cAvidaContext & ctx)5373 bool cHardwareCPU::Inst_DonateQuantaThreshGreenBeard(cAvidaContext& ctx)
5374 {
5375   // this donates to organisms that have this instruction anywhere
5376   // in their genome AND their parents excuted it more than a
5377   // THRESHOLD number of times where that threshold depend on the
5378   // number of times the individual's parents attempted to donate
5379   // using this instruction.  The threshold levels are multiples of
5380   // the quanta value set in avida.cfg, and the highest level that
5381   // the donor qualifies for is the one used.
5382 
5383   // (see Dawkins 1976, The Selfish Gene, for
5384   // the history of the theory and the name 'green beard'
5385   //  cout << "i am about to donate to a green beard" << endl;
5386   cPhenotype & phenotype = m_organism->GetPhenotype();
5387 
5388   if (phenotype.GetCurNumDonates() > m_world->GetConfig().MAX_DONATES.Get()) {
5389     return false;
5390   }
5391 
5392   phenotype.IncDonates();
5393   phenotype.SetIsDonorQuantaThreshGb();
5394   phenotype.IncNumQuantaThreshGbDonations();
5395   //cout << endl << "quanta_threshgb attempt.. " ;
5396 
5397 
5398   // Find the target as the first match found in the neighborhood.
5399 
5400   //get the neighborhood size
5401   const int num_neighbors = m_organism->GetNeighborhoodSize();
5402 
5403   // Turn to face a random neighbor
5404   int neighbor_id = ctx.GetRandom().GetInt(num_neighbors);
5405   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(1);
5406   cOrganism * neighbor = m_organism->GetNeighbor();
5407 
5408   int max_id = neighbor_id + num_neighbors;
5409 
5410   //we have not found a match yet
5411   bool found = false;
5412 
5413   // Get the quanta (step size) between threshold levels.
5414   const int donate_quanta = m_world->GetConfig().DONATE_THRESH_QUANTA.Get();
5415 
5416   // Calculate what quanta level we should be at for this individual.  We do a
5417   // math trick to make sure its the next lowest event multiple of donate_quanta.
5418   const int quanta_donate_thresh =
5419 	(phenotype.GetNumQuantaThreshGbDonationsLast() / donate_quanta) * donate_quanta;
5420   //cout << " phenotype.GetNumQuantaThreshGbDonationsLast() is " << phenotype.GetNumQuantaThreshGbDonationsLast();
5421   //cout << " quanta thresh=  " << quanta_donate_thresh;
5422   // rotate through orgs in neighborhood
5423   while (neighbor_id < max_id) {
5424     neighbor = m_organism->GetNeighbor();
5425     //if neighbor exists, AND if their parent attempted to donate >= threshhold,
5426     if (neighbor != NULL &&
5427 	neighbor->GetPhenotype().GetNumQuantaThreshGbDonationsLast() >= quanta_donate_thresh) {
5428 
5429       const Sequence& neighbor_genome = neighbor->GetGenome().GetSequence();
5430 
5431       // for each instruction in the genome...
5432       for (int i=0;i<neighbor_genome.GetSize();i++){
5433 
5434 	// ...see if it is donate-quantagb, if so, we found a target
5435 	if (neighbor_genome[i] == getIP().GetInst()) {
5436 	  found = true;
5437 	  break;
5438 	}
5439 
5440       }
5441     }
5442 
5443     // stop searching through the neighbors if we already found one
5444     if (found == true) {
5445       break;
5446     }
5447 
5448     m_organism->Rotate(1);
5449     neighbor_id++;
5450   }
5451 
5452   if (found == false) neighbor = NULL;
5453 
5454   // Put the facing back where it was.
5455   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(-1);
5456 
5457   // Donate only if we have found a close enough relative...
5458   if (neighbor != NULL) {
5459     DoDonate(neighbor);
5460     neighbor->GetPhenotype().SetIsReceiverQuantaThreshGb();
5461     //cout << " ************ neighbor->GetPhenotype().GetNumQuantaThreshGbDonationsLast() is " << neighbor->GetPhenotype().GetNumQuantaThreshGbDonationsLast();
5462 
5463   }
5464 
5465   return true;
5466 
5467 }
5468 
5469 
Inst_DonateGreenBeardSameLocus(cAvidaContext & ctx)5470 bool cHardwareCPU::Inst_DonateGreenBeardSameLocus(cAvidaContext& ctx)
5471 {
5472   // This instruction donates to organisms that have a matching instruction
5473   // at the same position in their genome AND their parents excuted it.
5474 
5475   cPhenotype & phenotype = m_organism->GetPhenotype();
5476 
5477   if (phenotype.GetCurNumDonates() > m_world->GetConfig().MAX_DONATES.Get()) {
5478     return false;
5479   }
5480 
5481   int donate_locus = getIP().GetPosition();
5482 
5483   phenotype.IncDonates();
5484   phenotype.SetIsDonorPosition(donate_locus);
5485   phenotype.IncNumGreenBeardSameLocus();
5486 
5487   // Find the target as the first match found in the neighborhood.
5488 
5489   //get the neighborhood size
5490   const int num_neighbors = m_organism->GetNeighborhoodSize();
5491 
5492   // Turn to face a random neighbor
5493   int neighbor_id = ctx.GetRandom().GetInt(num_neighbors);
5494   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(1);
5495   cOrganism * neighbor = m_organism->GetNeighbor();
5496 
5497   int max_id = neighbor_id + num_neighbors;
5498 
5499   // We have not found a match yet
5500   bool found = false;
5501 
5502   // Rotate through orgs in neighborhood
5503   while (neighbor_id < max_id) {
5504     neighbor = m_organism->GetNeighbor();
5505     // If neighbor exists, AND if their parent attempted to donate at this position.
5506     if (neighbor != NULL && neighbor->GetPhenotype().IsDonorPositionLast(donate_locus)) {
5507       const Sequence& neighbor_genome = neighbor->GetGenome().GetSequence();
5508       // See if this organism has a donate at the correct position.
5509       if (neighbor_genome.GetSize() > donate_locus && neighbor_genome[donate_locus] == getIP().GetInst()) {
5510         found = true;
5511         break;
5512       }
5513     }
5514 
5515     m_organism->Rotate(1);
5516     neighbor_id++;
5517   }
5518 
5519   if (found == false) neighbor = NULL;
5520 
5521   // Put the facing back where it was.
5522   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(-1);
5523 
5524   // Donate only if we have found a valid receiver
5525   if (neighbor != NULL) {
5526     DoDonate(neighbor);
5527     neighbor->GetPhenotype().SetIsReceiverGBSameLocus();
5528   }
5529 
5530   return true;
5531 
5532 }
5533 
5534 
Inst_DonateNULL(cAvidaContext & ctx)5535 bool cHardwareCPU::Inst_DonateNULL(cAvidaContext& ctx)
5536 {
5537   if (m_organism->GetPhenotype().GetCurNumDonates() > m_world->GetConfig().MAX_DONATES.Get()) {
5538     return false;
5539   }
5540 
5541   m_organism->GetPhenotype().IncDonates();
5542   m_organism->GetPhenotype().SetIsDonorNull();
5543 
5544   // This is a fake donate command that causes the organism to lose merit,
5545   // but no one else to gain any.
5546 
5547   const double merit_given = m_world->GetConfig().MERIT_GIVEN.Get();
5548   double cur_merit = m_organism->GetPhenotype().GetMerit().GetDouble();
5549   cur_merit -= merit_given;
5550 
5551   // Plug the current merit back into this organism and notify the scheduler.
5552   m_organism->UpdateMerit(cur_merit);
5553 
5554   return true;
5555 }
5556 
5557 
5558 //Move energy from an organism's received energy buffer into their energy store, recalculate merit
Inst_ReceiveDonatedEnergy(cAvidaContext & ctx)5559 bool cHardwareCPU::Inst_ReceiveDonatedEnergy(cAvidaContext& ctx)
5560 {
5561   if (m_organism->GetCellID() < 0) {
5562     return false;
5563   }
5564 
5565   cPhenotype& phenotype = m_organism->GetPhenotype();
5566   if (phenotype.GetEnergyInBufferAmount() > 0) {
5567     phenotype.ApplyDonatedEnergy();
5568 
5569     if (m_world->GetConfig().ENERGY_SHARING_UPDATE_METABOLIC.Get() == 1) {
5570       double receiverMerit = phenotype.ConvertEnergyToMerit(phenotype.GetStoredEnergy() * phenotype.GetEnergyUsageRatio());
5571       m_organism->UpdateMerit(receiverMerit);
5572     }
5573   }
5574 
5575   return true;
5576 
5577 } //End Inst_ReceiveDonatedEnergy()
5578 
5579 
5580 //Donate a fraction of organism's energy to the organism that last requested it.
Inst_DonateEnergy(cAvidaContext & ctx)5581 bool cHardwareCPU::Inst_DonateEnergy(cAvidaContext& ctx)
5582 {
5583   if (m_organism->GetCellID() < 0) {
5584     return false;
5585   }
5586 
5587   std::pair<bool, cOrgMessage> retrieved = m_organism->RetrieveMessage();
5588   if (!retrieved.first) {
5589     return false;
5590   }
5591 
5592   /* MJM - by this point, the pointer returned by GetSender() may no longer
5593    * be any good. Instead, we should use the cell and organism ID of the
5594    * message sender to get hold of the sender (if it still exists and hasn't moved)
5595    */
5596   cPopulationCell senderCell = m_world->GetPopulation().GetCell(retrieved.second.GetSenderCellID());
5597   if (!senderCell.IsOccupied()) {
5598     // the organism that made the request is gone, we can't donate...
5599     return false;
5600   }
5601   cOrganism* energyReceiver = senderCell.GetOrganism();
5602   if (energyReceiver->GetID() != retrieved.second.GetSenderOrgID()) {
5603     // some other organism has occupied this cell since the msg was sent,
5604     // we can't donate...
5605     return false;
5606   }
5607 
5608   DoEnergyDonatePercent(energyReceiver, m_organism->GetFracEnergyDonating());
5609 
5610   return true;
5611 
5612 } //End Inst_DonateEnergy()
5613 
5614 
5615 //Update the organism's metabolic rate
Inst_UpdateMetabolicRate(cAvidaContext & ctx)5616 bool cHardwareCPU::Inst_UpdateMetabolicRate(cAvidaContext& ctx)
5617 {
5618   cPhenotype& phenotype = m_organism->GetPhenotype();
5619   double newmerit = phenotype.ConvertEnergyToMerit(phenotype.GetStoredEnergy()  * phenotype.GetEnergyUsageRatio());
5620   m_organism->UpdateMerit(newmerit);
5621 
5622   return true;
5623 } //End Inst_UpdateMetabolocRate()
5624 
5625 
5626 //Donate a fraction of organism's energy to faced organism.
Inst_DonateEnergyFaced(cAvidaContext & ctx)5627 bool cHardwareCPU::Inst_DonateEnergyFaced(cAvidaContext& ctx)
5628 {
5629   if (m_organism->GetCellID() < 0) {
5630     return false;
5631   }
5632 
5633   cOrganism * neighbor = m_organism->GetNeighbor();
5634 
5635   if ( (neighbor != NULL) && (!neighbor->IsDead()) ) {
5636 
5637     // If the neighbor has requested energy or if we're allowing push sharing, share energy
5638     if ( (neighbor->GetPhenotype().HasOpenEnergyRequest()) || (m_world->GetConfig().ENERGY_SHARING_METHOD.Get() == 1) ) {
5639       DoEnergyDonatePercent(neighbor, m_organism->GetFracEnergyDonating());
5640     }
5641   }
5642 
5643   return true;
5644 
5645 } //End Inst_DonateEnergyFaced()
5646 
5647 
Inst_DonateEnergyFaced1(cAvidaContext & ctx)5648 bool cHardwareCPU::Inst_DonateEnergyFaced1(cAvidaContext& ctx)
5649 {
5650   if (m_organism->GetCellID() < 0) {
5651     return false;
5652   }
5653 
5654   cOrganism * neighbor = m_organism->GetNeighbor();
5655 
5656   if ( (neighbor != NULL) && (!neighbor->IsDead()) ) {
5657 
5658     // If the neighbor has requested energy or if we're allowing push sharing, share energy
5659     if ( (neighbor->GetPhenotype().HasOpenEnergyRequest()) || (m_world->GetConfig().ENERGY_SHARING_METHOD.Get() == 1) ) {
5660       DoEnergyDonateAmount(neighbor, 1);
5661     }
5662   }
5663 
5664   return true;
5665 
5666 } //End Inst_DonateEnergyFaced1()
5667 
5668 
Inst_DonateEnergyFaced2(cAvidaContext & ctx)5669 bool cHardwareCPU::Inst_DonateEnergyFaced2(cAvidaContext& ctx)
5670 {
5671   if (m_organism->GetCellID() < 0) {
5672     return false;
5673   }
5674 
5675   cOrganism * neighbor = m_organism->GetNeighbor();
5676 
5677   if ( (neighbor != NULL) && (!neighbor->IsDead()) ) {
5678 
5679     // If the neighbor has requested energy or if we're allowing push sharing, share energy
5680     if ( (neighbor->GetPhenotype().HasOpenEnergyRequest()) || (m_world->GetConfig().ENERGY_SHARING_METHOD.Get() == 1) ) {
5681       DoEnergyDonateAmount(neighbor, 2);
5682     }
5683   }
5684 
5685   return true;
5686 
5687 } //End Inst_DonateEnergyFaced2()
5688 
5689 
Inst_DonateEnergyFaced5(cAvidaContext & ctx)5690 bool cHardwareCPU::Inst_DonateEnergyFaced5(cAvidaContext& ctx)
5691 {
5692   if (m_organism->GetCellID() < 0) {
5693     return false;
5694   }
5695 
5696   cOrganism * neighbor = m_organism->GetNeighbor();
5697 
5698   if ( (neighbor != NULL) && (!neighbor->IsDead()) ) {
5699 
5700     // If the neighbor has requested energy or if we're allowing push sharing, share energy
5701     if ( (neighbor->GetPhenotype().HasOpenEnergyRequest()) || (m_world->GetConfig().ENERGY_SHARING_METHOD.Get() == 1) ) {
5702       DoEnergyDonateAmount(neighbor, 5);
5703     }
5704   }
5705 
5706   return true;
5707 
5708 } //End Inst_DonateEnergyFaced5()
5709 
5710 
Inst_DonateEnergyFaced10(cAvidaContext & ctx)5711 bool cHardwareCPU::Inst_DonateEnergyFaced10(cAvidaContext& ctx)
5712 {
5713   if (m_organism->GetCellID() < 0) {
5714     return false;
5715   }
5716 
5717   cOrganism * neighbor = m_organism->GetNeighbor();
5718 
5719   if ( (neighbor != NULL) && (!neighbor->IsDead()) ) {
5720 
5721     // If the neighbor has requested energy or if we're allowing push sharing, share energy
5722     if ( (neighbor->GetPhenotype().HasOpenEnergyRequest()) || (m_world->GetConfig().ENERGY_SHARING_METHOD.Get() == 1) ) {
5723       DoEnergyDonateAmount(neighbor, 10);
5724     }
5725   }
5726 
5727   return true;
5728 
5729 } //End Inst_DonateEnergyFaced10()
5730 
5731 
Inst_DonateEnergyFaced20(cAvidaContext & ctx)5732 bool cHardwareCPU::Inst_DonateEnergyFaced20(cAvidaContext& ctx)
5733 {
5734   if (m_organism->GetCellID() < 0) {
5735     return false;
5736   }
5737 
5738   cOrganism * neighbor = m_organism->GetNeighbor();
5739 
5740   if ( (neighbor != NULL) && (!neighbor->IsDead()) ) {
5741 
5742     // If the neighbor has requested energy or if we're allowing push sharing, share energy
5743     if ( (neighbor->GetPhenotype().HasOpenEnergyRequest()) || (m_world->GetConfig().ENERGY_SHARING_METHOD.Get() == 1) ) {
5744       DoEnergyDonateAmount(neighbor, 20);
5745     }
5746   }
5747 
5748   return true;
5749 
5750 } //End Inst_DonateEnergyFaced20()
5751 
5752 
Inst_DonateEnergyFaced50(cAvidaContext & ctx)5753 bool cHardwareCPU::Inst_DonateEnergyFaced50(cAvidaContext& ctx)
5754 {
5755   if (m_organism->GetCellID() < 0) {
5756     return false;
5757   }
5758 
5759   cOrganism * neighbor = m_organism->GetNeighbor();
5760 
5761   if ( (neighbor != NULL) && (!neighbor->IsDead()) ) {
5762 
5763     // If the neighbor has requested energy or if we're allowing push sharing, share energy
5764     if ( (neighbor->GetPhenotype().HasOpenEnergyRequest()) || (m_world->GetConfig().ENERGY_SHARING_METHOD.Get() == 1) ) {
5765       DoEnergyDonateAmount(neighbor, 50);
5766     }
5767   }
5768 
5769   return true;
5770 
5771 } //End Inst_DonateEnergyFaced50()
5772 
5773 
Inst_DonateEnergyFaced100(cAvidaContext & ctx)5774 bool cHardwareCPU::Inst_DonateEnergyFaced100(cAvidaContext& ctx)
5775 {
5776   if (m_organism->GetCellID() < 0) {
5777     return false;
5778   }
5779 
5780   cOrganism * neighbor = m_organism->GetNeighbor();
5781 
5782   if ( (neighbor != NULL) && (!neighbor->IsDead()) ) {
5783 
5784     // If the neighbor has requested energy or if we're allowing push sharing, share energy
5785     if ( (neighbor->GetPhenotype().HasOpenEnergyRequest()) || (m_world->GetConfig().ENERGY_SHARING_METHOD.Get() == 1) ) {
5786       DoEnergyDonateAmount(neighbor, 100);
5787     }
5788   }
5789 
5790   return true;
5791 
5792 } //End Inst_DonateEnergyFaced100()
5793 
5794 
5795 // Rotate to face the most energy needy neighbor
Inst_RotateToMostNeedy(cAvidaContext & ctx)5796 bool cHardwareCPU::Inst_RotateToMostNeedy(cAvidaContext& ctx)
5797 {
5798   if (m_organism->GetCellID() < 0) {
5799     return false;
5800   }
5801 
5802   cPopulation& pop = m_world->GetPopulation();
5803   cPopulationCell& mycell = pop.GetCell(m_organism->GetCellID());
5804 
5805   double min_energy = m_world->GetConfig().ENERGY_CAP.Get();
5806   int num_rotations = 0;
5807   cOrganism *neighbor;
5808   double neighbor_energy;
5809 
5810   // Look at the energy levels of neighbors
5811   for (int i = 0; i < mycell.ConnectionList().GetSize(); i++) {
5812     mycell.ConnectionList().CircNext();
5813     neighbor = m_organism->GetNeighbor();
5814 
5815     // If this neighbor is alive and has a request for energy or we're allowing pushing of energy, look at it
5816     if ( (neighbor != NULL) && (!neighbor->IsDead()) &&
5817         ((neighbor->GetPhenotype().HasOpenEnergyRequest()) || (m_world->GetConfig().ENERGY_SHARING_METHOD.Get() == 1)) ) {
5818       neighbor_energy = neighbor->GetPhenotype().GetStoredEnergy();
5819 
5820       if ( (neighbor_energy > 0) && (neighbor_energy < min_energy) ) {
5821         num_rotations = i;
5822       }
5823     }
5824 
5825   }
5826 
5827   //Rotate to face the most needy neighbor
5828   for (int i = 0; i < num_rotations; i++) {
5829     mycell.ConnectionList().CircNext();
5830   }
5831 
5832   return true;
5833 
5834 } //End Inst_RotateToMostNeedy()
5835 
5836 
5837 //Broadcast a request for energy
Inst_RequestEnergy(cAvidaContext & ctx)5838 bool cHardwareCPU::Inst_RequestEnergy(cAvidaContext& ctx)
5839 {
5840   if (m_organism->GetCellID() < 0) {
5841     return false;
5842   }
5843 
5844   cOrgMessage msg(m_organism);
5845   // Could set the data field of the message to be the multiplier
5846 
5847   m_organism->BroadcastMessage(ctx, msg, m_world->GetConfig().ENERGY_REQUEST_RADIUS.Get());
5848   m_organism->GetPhenotype().SetIsEnergyRequestor();
5849   m_organism->GetPhenotype().IncreaseNumEnergyRequests();
5850 
5851   return true;
5852 
5853 } //End Inst_RequestEnergy()
5854 
5855 
5856 //Set the request energy flag
Inst_RequestEnergyFlagOn(cAvidaContext & ctx)5857 bool cHardwareCPU::Inst_RequestEnergyFlagOn(cAvidaContext& ctx)
5858 {
5859   if (m_organism->GetCellID() < 0) {
5860     return false;
5861   }
5862 
5863   m_organism->GetPhenotype().SetIsEnergyRequestor();
5864   m_organism->GetPhenotype().IncreaseNumEnergyRequests();
5865   m_organism->GetPhenotype().SetHasOpenEnergyRequest();
5866 
5867   return true;
5868 } //End Inst_RequestEnergyFlagOn()
5869 
5870 
5871 //Set the request energy flag to off
Inst_RequestEnergyFlagOff(cAvidaContext & ctx)5872 bool cHardwareCPU::Inst_RequestEnergyFlagOff(cAvidaContext& ctx)
5873 {
5874   if (m_organism->GetCellID() < 0) {
5875     return false;
5876   }
5877 
5878   m_organism->GetPhenotype().ClearHasOpenEnergyRequest();
5879   return true;
5880 } //End Inst_RequestEnergyFlagOff()
5881 
5882 
5883 // Increase the amount of energy to be donated
Inst_IncreaseEnergyDonation(cAvidaContext & ctx)5884 bool cHardwareCPU::Inst_IncreaseEnergyDonation(cAvidaContext& ctx)
5885 {
5886   double curr_amount = m_organism->GetFracEnergyDonating();
5887   double increment = m_world->GetConfig().ENERGY_SHARING_INCREMENT.Get();
5888 
5889   m_organism->SetFracEnergyDonating(min(1.0, curr_amount + increment));
5890 
5891   return true;
5892 
5893 } //End Inst_IncreaseEnergyDonation()
5894 
5895 
5896 // Decrease the amount of energy to be donated
Inst_DecreaseEnergyDonation(cAvidaContext & ctx)5897 bool cHardwareCPU::Inst_DecreaseEnergyDonation(cAvidaContext& ctx)
5898 {
5899   double curr_amount = m_organism->GetFracEnergyDonating();
5900   double increment = m_world->GetConfig().ENERGY_SHARING_INCREMENT.Get();
5901 
5902   m_organism->SetFracEnergyDonating(max(0.0, curr_amount - increment));
5903 
5904   return true;
5905 
5906 } //End Inst_DecreaseEnergyDonation()
5907 
5908 
5909 // Move a fraction of the given resource present at the current cell to the specified cell.
5910 // Note: This function doesn't work with deme-level resources.
DoResourceDonatePercent(cAvidaContext & ctx,const int to_cell,const int resource_id,const double frac_resource_given)5911 void cHardwareCPU::DoResourceDonatePercent(cAvidaContext& ctx, const int to_cell, const int resource_id, const double frac_resource_given)
5912 {
5913   assert(to_cell >= 0);
5914   assert(resource_id >= 0);
5915   assert(frac_resource_given >= 0);
5916   assert(frac_resource_given <= 1);
5917 
5918   const tArray<double> &resources = m_organism->GetOrgInterface().GetResources(ctx);
5919   if (resource_id >= resources.GetSize()) return;
5920 
5921   const double amount = max(0.0, frac_resource_given * resources[resource_id]);
5922 
5923   DoResourceDonateAmount(ctx, to_cell, resource_id, amount);
5924 
5925 } //End DoResourceDonatePercent()
5926 
5927 
5928 // Donate a portion of the given resource present at the current cell to the specified cell.
5929 // Note: This function doesn't work with deme-level resources.
DoResourceDonateAmount(cAvidaContext & ctx,const int to_cell,const int resource_id,const double amount)5930 void cHardwareCPU::DoResourceDonateAmount(cAvidaContext& ctx, const int to_cell, const int resource_id, const double amount)
5931 {
5932   assert(to_cell >= 0);
5933   assert(amount >= 0);
5934   assert(resource_id >= 0);
5935 
5936   const tArray<double> &src_resources = m_organism->GetOrgInterface().GetResources(ctx);
5937   const tArray<double> &dest_resources = m_world->GetPopulation().GetCellResources(to_cell, ctx);
5938 
5939   assert(resource_id < src_resources.GetSize());
5940   assert(resource_id < dest_resources.GetSize());
5941 
5942   const double donation = min(amount, src_resources[resource_id]);
5943   const double decay = m_world->GetConfig().RESOURCE_SHARING_LOSS.Get();
5944 
5945   assert(decay >= 0);
5946   assert(decay <= 1);
5947 
5948   tArray<double> src_change;
5949   tArray<double> dest_change;
5950 
5951   src_change.Resize(src_resources.GetSize(), 0);
5952   dest_change.Resize(dest_resources.GetSize(), 0);
5953 
5954   src_change[resource_id] = -1 * donation;
5955   dest_change[resource_id] = (1 - decay) * donation;
5956 
5957   m_organism->GetOrgInterface().UpdateResources(ctx, src_change);
5958   m_world->GetPopulation().UpdateCellResources(ctx, dest_change, to_cell);
5959 
5960 } //End DoResourceDonateAmount()
5961 
5962 
5963 //Donate a fraction of nop-specified resource at organism's location to cell faced
DonateResourceX(cAvidaContext & ctx,const int res_id)5964 bool cHardwareCPU::DonateResourceX(cAvidaContext& ctx, const int res_id)
5965 {
5966   assert(m_organism != 0);
5967   assert(res_id >= 0);
5968 
5969   const double pct = 0.1;
5970 
5971   int current_cell, faced_cell;
5972 
5973   current_cell = m_organism->GetCellID();
5974 
5975   if (current_cell == -1) {
5976     return false;
5977   }
5978 
5979   cPopulation& pop = m_world->GetPopulation();
5980   faced_cell = pop.GetCell(current_cell).GetCellFaced().GetID();
5981 
5982   if (faced_cell == -1) {
5983     return false;
5984   }
5985 
5986   DoResourceDonatePercent(ctx, faced_cell, res_id, pct);
5987 
5988   return true;
5989 
5990 } //End DonateResourceX()
5991 
5992 
5993 //Donate a fraction of nop-specified resource at organism's location to cell faced
Inst_DonateResource0(cAvidaContext & ctx)5994 bool cHardwareCPU::Inst_DonateResource0(cAvidaContext& ctx)
5995 {
5996   return DonateResourceX(ctx ,0);
5997 } //End Inst_DonateResource0()
5998 
5999 
6000 //Donate a fraction of nop-specified resource at organism's location to cell faced
Inst_DonateResource1(cAvidaContext & ctx)6001 bool cHardwareCPU::Inst_DonateResource1(cAvidaContext& ctx)
6002 {
6003   return DonateResourceX(ctx, 1);
6004 } //End Inst_DonateResource1()
6005 
6006 //Donate a fraction of nop-specified resource at organism's location to cell faced
Inst_DonateResource2(cAvidaContext & ctx)6007 bool cHardwareCPU::Inst_DonateResource2(cAvidaContext& ctx)
6008 {
6009   return DonateResourceX(ctx, 2);
6010 } //End Inst_DonateResource2()
6011 
6012 
Inst_SearchF(cAvidaContext & ctx)6013 bool cHardwareCPU::Inst_SearchF(cAvidaContext& ctx)
6014 {
6015   ReadLabel();
6016   GetLabel().Rotate(1, NUM_NOPS);
6017   const int search_size = FindLabel(1).GetPosition() - getIP().GetPosition();
6018   GetRegister(REG_BX) = search_size;
6019   GetRegister(REG_CX) = GetLabel().GetSize();
6020   return true;
6021 }
6022 
Inst_SearchB(cAvidaContext & ctx)6023 bool cHardwareCPU::Inst_SearchB(cAvidaContext& ctx)
6024 {
6025   ReadLabel();
6026   GetLabel().Rotate(1, NUM_NOPS);
6027   const int search_size = getIP().GetPosition() - FindLabel(-1).GetPosition();
6028   GetRegister(REG_BX) = search_size;
6029   GetRegister(REG_CX) = GetLabel().GetSize();
6030   return true;
6031 }
6032 
Inst_MemSize(cAvidaContext & ctx)6033 bool cHardwareCPU::Inst_MemSize(cAvidaContext& ctx)
6034 {
6035   GetRegister(FindModifiedRegister(REG_BX)) = m_memory.GetSize();
6036   return true;
6037 }
6038 
Inst_IOBufAdd1(cAvidaContext & ctx)6039 bool cHardwareCPU::Inst_IOBufAdd1(cAvidaContext& ctx)
6040 {
6041   m_organism->AddOutput(1);
6042   return true;
6043 }
Inst_IOBufAdd0(cAvidaContext & ctx)6044 bool cHardwareCPU::Inst_IOBufAdd0(cAvidaContext& ctx)
6045 {
6046   m_organism->AddOutput(0);
6047   return true;
6048 }
6049 
Inst_RotateL(cAvidaContext & ctx)6050 bool cHardwareCPU::Inst_RotateL(cAvidaContext& ctx)
6051 {
6052   const int num_neighbors = m_organism->GetNeighborhoodSize();
6053 
6054   // If this organism has no neighbors, ignore rotate.
6055   if (num_neighbors == 0) return false;
6056 
6057   ReadLabel();
6058 
6059   // Always rotate at least once.
6060   m_organism->Rotate(-1);
6061 
6062   // If there is no label, then the one rotation was all we want.
6063   if (!GetLabel().GetSize()) return true;
6064 
6065   // Rotate until a complement label is found (or all have been checked).
6066   GetLabel().Rotate(1, NUM_NOPS);
6067   for (int i = 1; i < num_neighbors; i++) {
6068     cOrganism* neighbor = m_organism->GetNeighbor();
6069 
6070     if (neighbor != NULL && neighbor->GetHardware().FindLabelFull(GetLabel()).InMemory()) return true;
6071 
6072     // Otherwise keep rotating...
6073     m_organism->Rotate(1);
6074   }
6075   return true;
6076 }
6077 
Inst_RotateR(cAvidaContext & ctx)6078 bool cHardwareCPU::Inst_RotateR(cAvidaContext& ctx)
6079 {
6080   const int num_neighbors = m_organism->GetNeighborhoodSize();
6081 
6082   // If this organism has no neighbors, ignore rotate.
6083   if (num_neighbors == 0) return false;
6084 
6085   ReadLabel();
6086 
6087   // Always rotate at least once.
6088   m_organism->Rotate(1);
6089 
6090   // If there is no label, then the one rotation was all we want.
6091   if (!GetLabel().GetSize()) return true;
6092 
6093   // Rotate until a complement label is found (or all have been checked).
6094   GetLabel().Rotate(1, NUM_NOPS);
6095   for (int i = 1; i < num_neighbors; i++) {
6096     cOrganism* neighbor = m_organism->GetNeighbor();
6097 
6098     if (neighbor != NULL && neighbor->GetHardware().FindLabelFull(GetLabel()).InMemory()) return true;
6099 
6100     // Otherwise keep rotating...
6101     m_organism->Rotate(-1);
6102   }
6103   return true;
6104 }
6105 
Inst_RotateLeftOne(cAvidaContext & ctx)6106 bool cHardwareCPU::Inst_RotateLeftOne(cAvidaContext& ctx)
6107 {
6108   m_organism->Rotate(1);
6109   return true;
6110 }
6111 
Inst_RotateRightOne(cAvidaContext & ctx)6112 bool cHardwareCPU::Inst_RotateRightOne(cAvidaContext& ctx)
6113 {
6114   m_organism->Rotate(-1);
6115   return true;
6116 }
6117 
6118 /**
6119  Rotate to facing specified by following label
6120  */
Inst_RotateLabel(cAvidaContext & ctx)6121 bool cHardwareCPU::Inst_RotateLabel(cAvidaContext& ctx)
6122 {
6123   int standardNeighborhoodSize, actualNeighborhoodSize, newFacing, currentFacing;
6124   actualNeighborhoodSize = m_organism->GetNeighborhoodSize();
6125 
6126   ReadLabel();
6127   if (m_world->GetConfig().WORLD_GEOMETRY.Get() == nGeometry::TORUS ||
6128       m_world->GetConfig().WORLD_GEOMETRY.Get() == nGeometry::GRID) {
6129     standardNeighborhoodSize = 8;
6130   } else {
6131     exit(-1);
6132   }
6133   newFacing = GetLabel().AsIntGreyCode(NUM_NOPS) % standardNeighborhoodSize;
6134 
6135   for (int i = 0; i < actualNeighborhoodSize; i++) {
6136     currentFacing = m_organism->GetFacing();
6137     if (newFacing == currentFacing)
6138       break;
6139     m_organism->Rotate(1);
6140   }
6141   return true;
6142 }
6143 
Inst_RotateUnoccupiedCell(cAvidaContext & ctx)6144 bool cHardwareCPU::Inst_RotateUnoccupiedCell(cAvidaContext& ctx)
6145 {
6146   const int reg_used = FindModifiedRegister(REG_BX);
6147 
6148   for (int i = 0; i < m_organism->GetNeighborhoodSize(); i++) {
6149     if (!m_organism->IsNeighborCellOccupied()) { // faced cell is unoccupied
6150       GetRegister(reg_used) = 1;
6151       return true;
6152     }
6153     m_organism->Rotate(1); // continue to rotate
6154   }
6155   GetRegister(reg_used) = 0;
6156   return true;
6157 }
6158 
Inst_RotateOccupiedCell(cAvidaContext & ctx)6159 bool cHardwareCPU::Inst_RotateOccupiedCell(cAvidaContext& ctx)
6160 {
6161   const int reg_used = FindModifiedRegister(REG_BX);
6162 
6163   for (int i = 0; i < m_organism->GetNeighborhoodSize(); i++) {
6164     if (m_organism->IsNeighborCellOccupied()) { // faced cell is occupied
6165       GetRegister(reg_used) = 1;
6166       return true;
6167     }
6168     m_organism->Rotate(1); // continue to rotate
6169   }
6170   GetRegister(reg_used) = 0;
6171   return true;
6172 }
6173 
Inst_RotateNextOccupiedCell(cAvidaContext & ctx)6174 bool cHardwareCPU::Inst_RotateNextOccupiedCell(cAvidaContext& ctx)
6175 {
6176   m_organism->Rotate(1);
6177   return Inst_RotateOccupiedCell(ctx);
6178 }
6179 
Inst_RotateNextUnoccupiedCell(cAvidaContext & ctx)6180 bool cHardwareCPU::Inst_RotateNextUnoccupiedCell(cAvidaContext& ctx)
6181 {
6182   m_organism->Rotate(1); // continue to rotate
6183   return Inst_RotateUnoccupiedCell(ctx);
6184 }
6185 
Inst_RotateEventCell(cAvidaContext & ctx)6186 bool cHardwareCPU::Inst_RotateEventCell(cAvidaContext& ctx)
6187 {
6188   const int reg_used = FindModifiedRegister(REG_BX);
6189 
6190   for (int i = 0; i < m_organism->GetNeighborhoodSize(); i++) {
6191     if (m_organism->GetCellData() > 0) { // event in faced cell
6192       GetRegister(reg_used) = 1;
6193       return true;
6194     }
6195     m_organism->Rotate(1); // continue to rotate
6196   }
6197   GetRegister(reg_used) = 0;
6198   return true;
6199 }
6200 
Inst_RotateUphill(cAvidaContext & ctx)6201 bool cHardwareCPU::Inst_RotateUphill(cAvidaContext& ctx)
6202 {
6203   int actualNeighborhoodSize = m_organism->GetNeighborhoodSize();
6204   int opinion = 0;
6205 
6206   if(m_organism->GetOrgInterface().HasOpinion(m_organism)) opinion = m_organism->GetOpinion().first;
6207 
6208   const tArray<double> current_res = m_organism->GetOrgInterface().GetResources(ctx);
6209   double max_res = 0;
6210   for(int i = 0; i < actualNeighborhoodSize; i++) {
6211     m_organism->Rotate(1);
6212     tArray<double> faced_res = m_organism->GetOrgInterface().GetFacedCellResources(ctx);
6213     if (faced_res[opinion] > max_res) max_res = faced_res[opinion];
6214   }
6215 
6216   if (max_res > current_res[opinion]) {
6217     for(int i = 0; i < actualNeighborhoodSize; i++) {
6218       tArray<double> faced_res = m_organism->GetOrgInterface().GetFacedCellResources(ctx);
6219       if (faced_res[opinion] != max_res) m_organism->Rotate(1);
6220     }
6221   }
6222   // return % change
6223   int res_diff = 0;
6224   if (current_res[opinion] == 0) res_diff = (int) max_res;
6225   else res_diff = (int) (((max_res - current_res[opinion])/current_res[opinion]) * 100 + 0.5);
6226   int reg_to_set = FindModifiedRegister(REG_BX);
6227   GetRegister(reg_to_set) = res_diff;
6228   return true;
6229 }
6230 
Inst_RotateHome(cAvidaContext & ctx)6231 bool cHardwareCPU::Inst_RotateHome(cAvidaContext& ctx)
6232 {
6233   // Will rotate organism to face birth cell if org never used zero-easterly or zero-northerly. Otherwise will rotate org
6234   // to face the 'marked' spot where those instructions were executed.
6235   int easterly = m_organism->GetEasterly();
6236   int northerly = m_organism->GetNortherly();
6237   int correct_facing = 0;
6238   if (northerly > 0 && easterly == 0) correct_facing = 0; // rotate N
6239   else if (northerly > 0 && easterly < 0) correct_facing = 1; // rotate NE
6240   else if (northerly == 0 && easterly < 0) correct_facing = 2; // rotate E
6241   else if (northerly < 0 && easterly < 0) correct_facing = 3; // rotate SE
6242   else if (northerly < 0 && easterly == 0) correct_facing = 4; // rotate S
6243   else if (northerly < 0 && easterly > 0) correct_facing = 5; // rotate SW
6244   else if (northerly == 0 && easterly > 0) correct_facing = 6; // rotate W
6245   else if (northerly > 0 && easterly > 0) correct_facing = 7; // rotate NW
6246   for (int i = 0; i < m_organism->GetNeighborhoodSize(); i++) {
6247     m_organism->Rotate(1);
6248     if (m_organism->GetFacedDir() == correct_facing) break;
6249   }
6250   return true;
6251 }
6252 
Inst_SetCopyMut(cAvidaContext & ctx)6253 bool cHardwareCPU::Inst_SetCopyMut(cAvidaContext& ctx)
6254 {
6255   const int reg_used = FindModifiedRegister(REG_BX);
6256   const int new_mut_rate = Max(GetRegister(reg_used), 1 );
6257   m_organism->SetCopyMutProb(static_cast<double>(new_mut_rate) / 10000.0);
6258   return true;
6259 }
6260 
Inst_ModCopyMut(cAvidaContext & ctx)6261 bool cHardwareCPU::Inst_ModCopyMut(cAvidaContext& ctx)
6262 {
6263   const int reg_used = FindModifiedRegister(REG_BX);
6264   const double new_mut_rate = m_organism->GetCopyMutProb() + static_cast<double>(GetRegister(reg_used)) / 10000.0;
6265   if (new_mut_rate > 0.0) m_organism->SetCopyMutProb(new_mut_rate);
6266   return true;
6267 }
6268 
6269 // @WRE addition for movement
6270 // Tumble sets the organism and cell to a new random facing
6271 //
Inst_Tumble(cAvidaContext & ctx)6272 bool cHardwareCPU::Inst_Tumble(cAvidaContext& ctx)
6273 {
6274   // Get number of neighbor cells that the organism can move to.
6275   const int num_neighbors = m_organism->GetNeighborhoodSize();
6276   // Exclude extreme case of the completely disconnected cell
6277   if (0 < num_neighbors) {
6278     // Choose a base 0 random number of turns to make in facing, [0 .. num_neighbors-2].
6279     int irot = ctx.GetRandom().GetUInt(num_neighbors-1);
6280     // Treat as base 0 number of turns to make
6281     for (int i = 0; i <= irot; i++) {
6282       m_organism->Rotate(1);
6283     }
6284   }
6285   // Logging
6286   // ofstream tumblelog;
6287   // tumblelog.open("data/tumblelog.txt",ios::app);
6288   // tumblelog << organism->GetID() << "," << irot << endl;
6289   // tumblelog.close();
6290 
6291   return true;
6292 }
6293 
6294 
Inst_SGMove(cAvidaContext & ctx)6295 bool cHardwareCPU::Inst_SGMove(cAvidaContext& ctx)
6296 {
6297   assert(m_ext_mem.GetSize() > 3);
6298 
6299   const cStateGrid& sg = m_organism->GetStateGrid();
6300 
6301   int& x = m_ext_mem[0];
6302   int& y = m_ext_mem[1];
6303 
6304   const int facing = m_ext_mem[2];
6305 
6306   // State grid is treated as a 2-dimensional toroidal grid with size [0, width) and [0, height)
6307   // State grid is treated as a 2-dimensional toroidal grid with size [0, width) and [0, height)
6308   switch (facing) {
6309     case 0: // N
6310       if (++y == sg.GetHeight()) y = 0;
6311       break;
6312 
6313     case 1: // NE
6314       if (++x == sg.GetWidth()) x = 0;
6315       if (++y == sg.GetHeight()) y = 0;
6316       break;
6317 
6318     case 2: // E
6319       if (++x == sg.GetWidth()) x = 0;
6320       break;
6321 
6322     case 3: // SE
6323       if (++x == sg.GetWidth()) x = 0;
6324       if (--y == -1) y = sg.GetHeight() - 1;
6325       break;
6326 
6327     case 4: // S
6328       if (--y == -1) y = sg.GetHeight() - 1;
6329       break;
6330 
6331     case 5: // SW
6332       if (--x == -1) x = sg.GetWidth() - 1;
6333       if (--y == -1) y = sg.GetHeight() - 1;
6334       break;
6335 
6336     case 6: // W
6337       if (--x == -1) x = sg.GetWidth() - 1;
6338       break;
6339 
6340     case 7: // NW
6341       if (--x == -1) x = sg.GetWidth() - 1;
6342       if (++y == sg.GetHeight()) y = 0;
6343       break;
6344 
6345     default:
6346       assert(facing >= 0 && facing <= 7);
6347   }
6348 
6349   // Increment state observed count
6350   m_ext_mem[3 + sg.GetStateAt(x, y)]++;
6351 
6352   // Save this location in the movement history
6353   m_ext_mem.Push(sg.GetIDFor(x, y));
6354   return true;
6355 }
6356 
Inst_SGRotateL(cAvidaContext & ctx)6357 bool cHardwareCPU::Inst_SGRotateL(cAvidaContext& ctx)
6358 {
6359   assert(m_ext_mem.GetSize() > 3);
6360   if (--m_ext_mem[2] < 0) m_ext_mem[2] = 7;
6361   return true;
6362 }
6363 
Inst_SGRotateR(cAvidaContext & ctx)6364 bool cHardwareCPU::Inst_SGRotateR(cAvidaContext& ctx)
6365 {
6366   assert(m_ext_mem.GetSize() > 3);
6367   if (++m_ext_mem[2] > 7) m_ext_mem[2] = 0;
6368   return true;
6369 }
6370 
Inst_SGSense(cAvidaContext & ctx)6371 bool cHardwareCPU::Inst_SGSense(cAvidaContext& ctx)
6372 {
6373   const cStateGrid& sg = m_organism->GetStateGrid();
6374   const int reg_used = FindModifiedRegister(REG_BX);
6375   GetRegister(reg_used) = sg.SenseStateAt(m_ext_mem[0], m_ext_mem[1]);
6376   return true;
6377 }
6378 
6379 // @WRE addition for movement
6380 // Move uses the cPopulation::SwapCells method to move an m_organism to a different cell
6381 // and the cPopulation::MoveOrganisms helper function to clean up after a move
6382 // The cell selected as a destination is the one faced
Inst_Move(cAvidaContext & ctx)6383 bool cHardwareCPU::Inst_Move(cAvidaContext& ctx)
6384 {
6385   // In TestCPU, movement fails...
6386   if (m_organism->GetCellID() == -1) return false;
6387 
6388   bool move_success = m_organism->Move(ctx);
6389   const int out_reg = FindModifiedRegister(REG_BX);
6390   GetRegister(out_reg) = move_success;
6391   return true;
6392 }
6393 
Inst_MoveToEvent(cAvidaContext & ctx)6394 bool cHardwareCPU::Inst_MoveToEvent(cAvidaContext& ctx)
6395 {
6396   const int reg_used = FindModifiedRegister(REG_BX);
6397 
6398   for (int i = 0; i < m_organism->GetNeighborhoodSize(); i++) {
6399     if (m_organism->GetNeighborCellContents() > 0) {
6400       Inst_Move(ctx);
6401       GetRegister(reg_used) = 1;
6402       return true;
6403     }
6404     m_organism->Rotate(1);
6405   }
6406   Inst_Move(ctx);
6407   GetRegister(reg_used) = 0;
6408   return true;
6409 }
6410 
Inst_IfNeighborEventInUnoccupiedCell(cAvidaContext & ctx)6411 bool cHardwareCPU::Inst_IfNeighborEventInUnoccupiedCell(cAvidaContext& ctx)
6412 {
6413   for (int i = 0; i < m_organism->GetNeighborhoodSize(); i++) {
6414     if (m_organism->GetNeighborCellContents() > 0 && !m_organism->IsNeighborCellOccupied()) {
6415       return true;
6416     }
6417     m_organism->Rotate(1);
6418   }
6419   getIP().Advance();
6420   return true;
6421 }
6422 
Inst_IfFacingEventCell(cAvidaContext & ctx)6423 bool cHardwareCPU::Inst_IfFacingEventCell(cAvidaContext& ctx)
6424 {
6425   if (m_organism->GetNeighborCellContents() > 0) {
6426     return true;
6427   }
6428   getIP().Advance();
6429   return true;
6430 }
6431 
Inst_IfEventInCell(cAvidaContext & ctx)6432 bool cHardwareCPU::Inst_IfEventInCell(cAvidaContext& ctx)
6433 {
6434   if (m_organism->GetCellData() > 0) {
6435     return true;
6436   }
6437   getIP().Advance();
6438   return true;
6439 }
6440 
6441 // Multi-threading.
Inst_ForkThread(cAvidaContext & ctx)6442 bool cHardwareCPU::Inst_ForkThread(cAvidaContext& ctx)
6443 {
6444   getIP().Advance();
6445   if (!ForkThread()) m_organism->Fault(FAULT_LOC_THREAD_FORK, FAULT_TYPE_FORK_TH);
6446   return true;
6447 }
6448 
Inst_ForkThreadLabel(cAvidaContext & ctx)6449 bool cHardwareCPU::Inst_ForkThreadLabel(cAvidaContext& ctx)
6450 {
6451   ReadLabel();
6452   GetLabel().Rotate(1, NUM_NOPS);
6453 
6454   // If there is no label, then do normal fork behavior
6455   if (GetLabel().GetSize() == 0) {
6456     return Inst_ForkThread(ctx);
6457   }
6458 
6459   cHeadCPU searchHead = FindLabel(+1);
6460   if ( searchHead.GetPosition() != getIP().GetPosition() ) {
6461     int save_pos = getIP().GetPosition();
6462     getIP().Set(searchHead.GetPosition() + 1);
6463     if (!ForkThread()) m_organism->Fault(FAULT_LOC_THREAD_FORK, FAULT_TYPE_FORK_TH);
6464     getIP().Set( save_pos );
6465   }
6466 
6467   return true;
6468 }
6469 
Inst_ForkThreadLabelIfNot0(cAvidaContext & ctx)6470 bool cHardwareCPU::Inst_ForkThreadLabelIfNot0(cAvidaContext& ctx)
6471 {
6472   if (GetRegister(REG_BX) == 0) {
6473     ReadLabel();
6474     return false;
6475   }
6476   return Inst_ForkThreadLabel(ctx);
6477 }
6478 
Inst_ForkThreadLabelIf0(cAvidaContext & ctx)6479 bool cHardwareCPU::Inst_ForkThreadLabelIf0(cAvidaContext& ctx)
6480 {
6481   if (GetRegister(REG_BX) != 0) {
6482     ReadLabel();
6483     return false;
6484   }
6485   return Inst_ForkThreadLabel(ctx);
6486 }
6487 
Inst_KillThread(cAvidaContext & ctx)6488 bool cHardwareCPU::Inst_KillThread(cAvidaContext& ctx)
6489 {
6490   if (!KillThread()) m_organism->Fault(FAULT_LOC_THREAD_KILL, FAULT_TYPE_KILL_TH);
6491   else m_advance_ip = false;
6492   return true;
6493 }
6494 
Inst_ThreadID(cAvidaContext & ctx)6495 bool cHardwareCPU::Inst_ThreadID(cAvidaContext& ctx)
6496 {
6497   const int reg_used = FindModifiedRegister(REG_BX);
6498   GetRegister(reg_used) = GetCurThreadID();
6499   return true;
6500 }
6501 
6502 
6503 // Head-based instructions
6504 
Inst_SetHead(cAvidaContext & ctx)6505 bool cHardwareCPU::Inst_SetHead(cAvidaContext& ctx)
6506 {
6507   const int head_used = FindModifiedHead(nHardware::HEAD_IP);
6508   m_threads[m_cur_thread].cur_head = static_cast<unsigned char>(head_used);
6509   return true;
6510 }
6511 
Inst_AdvanceHead(cAvidaContext & ctx)6512 bool cHardwareCPU::Inst_AdvanceHead(cAvidaContext& ctx)
6513 {
6514   const int head_used = FindModifiedHead(nHardware::HEAD_WRITE);
6515   getHead(head_used).Advance();
6516   return true;
6517 }
6518 
Inst_MoveHead(cAvidaContext & ctx)6519 bool cHardwareCPU::Inst_MoveHead(cAvidaContext& ctx)
6520 {
6521   const int head_used = FindModifiedHead(nHardware::HEAD_IP);
6522   const int target = nHardware::HEAD_FLOW;
6523   getHead(head_used).Set(getHead(target));
6524   if (head_used == nHardware::HEAD_IP) m_advance_ip = false;
6525   return true;
6526 }
6527 
Inst_ResMoveHead(cAvidaContext & ctx)6528 bool cHardwareCPU::Inst_ResMoveHead(cAvidaContext& ctx)
6529 {
6530   const cString& resname = m_world->GetConfig().INST_RES.Get();
6531   const double floor = m_world->GetConfig().INST_RES_FLOOR.Get();
6532   const double ceil = m_world->GetConfig().INST_RES_CEIL.Get();
6533   double current_level=0;
6534 
6535   assert(floor >= 0);
6536   assert(ceil >= 0);
6537   assert(ceil >= floor);
6538 
6539   cPopulation& pop = m_world->GetPopulation();
6540   cDeme &deme = pop.GetDeme(pop.GetCell(m_organism->GetCellID()).GetDemeID());
6541 
6542   const cResourceCount& deme_resources = deme.GetDemeResourceCount();
6543   const cResourceCount& resources = pop.GetResourceCount();
6544 
6545   int resid = deme_resources.GetResourceByName(resname);
6546 
6547   if (resid >= 0) {
6548     current_level = deme_resources.Get(ctx, resid);
6549   } else if ( (resid = resources.GetResourceByName(resname)) >= 0) {
6550     current_level = resources.Get(ctx, resid);
6551   } else {
6552     cout << "Error: Cannot find resource '" << resname << "'" << endl;
6553     return true;
6554   }
6555 
6556   double current_frac = (current_level - floor) / (ceil - floor);
6557 
6558   if (ctx.GetRandom().P(current_frac)) {
6559     //cout << "Doing move-head with current resource fraction is: " << current_frac << " (floor: " << floor << ") (ceil: " << ceil << ") (level: " << current_level << ")"<<endl;
6560 
6561     return Inst_MoveHead(ctx);
6562   } else {
6563     //cout << "not doing jump" << endl;
6564   }
6565 
6566   return true;
6567 }
6568 
Inst_JumpHead(cAvidaContext & ctx)6569 bool cHardwareCPU::Inst_JumpHead(cAvidaContext& ctx)
6570 {
6571   const int head_used = FindModifiedHead(nHardware::HEAD_IP);
6572   getHead(head_used).Jump(GetRegister(REG_CX) );
6573   // @JEB - probably shouldn't advance IP after jumping here?
6574   // Any negative number jumps to the beginning of the genome (pos 0)
6575   // and then we immediately advance past that first instruction.
6576   return true;
6577 }
6578 
Inst_ResJumpHead(cAvidaContext & ctx)6579 bool cHardwareCPU::Inst_ResJumpHead(cAvidaContext& ctx)
6580 {
6581   const cString& resname = m_world->GetConfig().INST_RES.Get();
6582   const double floor = m_world->GetConfig().INST_RES_FLOOR.Get();
6583   const double ceil = m_world->GetConfig().INST_RES_CEIL.Get();
6584   double current_level=0;
6585 
6586   assert(floor >= 0);
6587   assert(ceil >= 0);
6588   assert(ceil >= floor);
6589 
6590   cPopulation& pop = m_world->GetPopulation();
6591   cDeme &deme = pop.GetDeme(pop.GetCell(m_organism->GetCellID()).GetDemeID());
6592 
6593   const cResourceCount& deme_resources = deme.GetDemeResourceCount();
6594   const cResourceCount& resources = pop.GetResourceCount();
6595 
6596   int resid = deme_resources.GetResourceByName(resname);
6597 
6598   if (resid >= 0) {
6599     current_level = deme_resources.Get(ctx, resid);
6600   } else if ( (resid = resources.GetResourceByName(resname)) >= 0) {
6601     current_level = resources.Get(ctx, resid);
6602   } else {
6603     cout << "Error: Cannot find resource '" << resname << "'" << endl;
6604     return true;
6605   }
6606 
6607   double current_frac = (current_level - floor) / (ceil - floor);
6608 
6609   if (ctx.GetRandom().P(current_frac)) {
6610     return Inst_JumpHead(ctx);
6611   }
6612 
6613   return true;
6614 }
6615 
6616 
Inst_GetHead(cAvidaContext & ctx)6617 bool cHardwareCPU::Inst_GetHead(cAvidaContext& ctx)
6618 {
6619   const int head_used = FindModifiedHead(nHardware::HEAD_IP);
6620   GetRegister(REG_CX) = getHead(head_used).GetPosition();
6621   return true;
6622 }
6623 
Inst_IfLabel(cAvidaContext & ctx)6624 bool cHardwareCPU::Inst_IfLabel(cAvidaContext& ctx)
6625 {
6626   ReadLabel();
6627   GetLabel().Rotate(1, NUM_NOPS);
6628   if (GetLabel() != GetReadLabel())  getIP().Advance();
6629   return true;
6630 }
6631 
Inst_IfLabelDirect(cAvidaContext & ctx)6632 bool cHardwareCPU::Inst_IfLabelDirect(cAvidaContext& ctx)
6633 {
6634   ReadLabel();
6635   if (GetLabel() != GetReadLabel())  getIP().Advance();
6636   return true;
6637 }
6638 
6639 // This is a variation on IfLabel that will skip the next command if the "if"
6640 // is false, but it will also skip all nops following that command.
Inst_IfLabel2(cAvidaContext & ctx)6641 bool cHardwareCPU::Inst_IfLabel2(cAvidaContext& ctx)
6642 {
6643   ReadLabel();
6644   GetLabel().Rotate(1, NUM_NOPS);
6645   if (GetLabel() != GetReadLabel()) {
6646     getIP().Advance();
6647     if (m_inst_set->IsNop( getIP().GetNextInst() ))  getIP().Advance();
6648   }
6649   return true;
6650 }
6651 
Inst_HeadDivideMut(cAvidaContext & ctx,double mut_multiplier)6652 bool cHardwareCPU::Inst_HeadDivideMut(cAvidaContext& ctx, double mut_multiplier)
6653 {
6654   AdjustHeads();
6655   const int divide_pos = getHead(nHardware::HEAD_READ).GetPosition();
6656   int child_end =  getHead(nHardware::HEAD_WRITE).GetPosition();
6657   if (child_end == 0) child_end = m_memory.GetSize();
6658   const int extra_lines = m_memory.GetSize() - child_end;
6659   bool ret_val = Divide_Main(ctx, divide_pos, extra_lines, mut_multiplier);
6660   // Re-adjust heads.
6661   AdjustHeads();
6662 
6663   // If using tolerance and a successful divide, place in BX register if the offspring was born into parent's group.
6664   if (m_world->GetConfig().TOLERANCE_WINDOW.Get() && ret_val) {
6665 	  GetRegister(REG_BX) = (int) m_organism->GetPhenotype().BornParentGroup();
6666   }
6667 
6668   return ret_val;
6669 }
6670 
Inst_HeadDivide(cAvidaContext & ctx)6671 bool cHardwareCPU::Inst_HeadDivide(cAvidaContext& ctx)
6672 {
6673   return Inst_HeadDivideMut(ctx, 1);
6674 
6675 }
6676 
6677 /*
6678  Resample Divide -- AWC 06/29/06
6679  */
6680 
Inst_HeadDivideRS(cAvidaContext & ctx)6681 bool cHardwareCPU::Inst_HeadDivideRS(cAvidaContext& ctx)
6682 {
6683   AdjustHeads();
6684   const int divide_pos = getHead(nHardware::HEAD_READ).GetPosition();
6685   int child_end =  getHead(nHardware::HEAD_WRITE).GetPosition();
6686   if (child_end == 0) child_end = m_memory.GetSize();
6687   const int extra_lines = m_memory.GetSize() - child_end;
6688   bool ret_val = Divide_MainRS(ctx, divide_pos, extra_lines, 1);
6689   // Re-adjust heads.
6690   AdjustHeads();
6691   return ret_val;
6692 }
6693 
6694 /*
6695  Resample Divide -- single mut on divide-- AWC 07/28/06
6696  */
6697 
Inst_HeadDivide1RS(cAvidaContext & ctx)6698 bool cHardwareCPU::Inst_HeadDivide1RS(cAvidaContext& ctx)
6699 {
6700   AdjustHeads();
6701   const int divide_pos = getHead(nHardware::HEAD_READ).GetPosition();
6702   int child_end =  getHead(nHardware::HEAD_WRITE).GetPosition();
6703   if (child_end == 0) child_end = m_memory.GetSize();
6704   const int extra_lines = m_memory.GetSize() - child_end;
6705   bool ret_val = Divide_Main1RS(ctx, divide_pos, extra_lines, 1);
6706   // Re-adjust heads.
6707   AdjustHeads();
6708   return ret_val;
6709 }
6710 
6711 /*
6712  Resample Divide -- double mut on divide-- AWC 08/29/06
6713  */
6714 
Inst_HeadDivide2RS(cAvidaContext & ctx)6715 bool cHardwareCPU::Inst_HeadDivide2RS(cAvidaContext& ctx)
6716 {
6717   AdjustHeads();
6718   const int divide_pos = getHead(nHardware::HEAD_READ).GetPosition();
6719   int child_end =  getHead(nHardware::HEAD_WRITE).GetPosition();
6720   if (child_end == 0) child_end = m_memory.GetSize();
6721   const int extra_lines = m_memory.GetSize() - child_end;
6722   bool ret_val = Divide_Main2RS(ctx, divide_pos, extra_lines, 1);
6723   // Re-adjust heads.
6724   AdjustHeads();
6725   return ret_val;
6726 }
6727 
6728 
Inst_HeadDivideSex(cAvidaContext & ctx)6729 bool cHardwareCPU::Inst_HeadDivideSex(cAvidaContext& ctx)
6730 {
6731   m_organism->GetPhenotype().SetDivideSex(true);
6732   m_organism->GetPhenotype().SetCrossNum(1);
6733   return Inst_HeadDivide(ctx);
6734 }
6735 
Inst_HeadDivideAsex(cAvidaContext & ctx)6736 bool cHardwareCPU::Inst_HeadDivideAsex(cAvidaContext& ctx)
6737 {
6738   m_organism->GetPhenotype().SetDivideSex(false);
6739   m_organism->GetPhenotype().SetCrossNum(0);
6740   return Inst_HeadDivide(ctx);
6741 }
6742 
Inst_HeadDivideAsexWait(cAvidaContext & ctx)6743 bool cHardwareCPU::Inst_HeadDivideAsexWait(cAvidaContext& ctx)
6744 {
6745   m_organism->GetPhenotype().SetDivideSex(true);
6746   m_organism->GetPhenotype().SetCrossNum(0);
6747   return Inst_HeadDivide(ctx);
6748 }
6749 
Inst_HeadDivideMateSelect(cAvidaContext & ctx)6750 bool cHardwareCPU::Inst_HeadDivideMateSelect(cAvidaContext& ctx)
6751 {
6752   // Take the label that follows this divide and use it as the ID for which
6753   // other organisms this one is willing to mate with.
6754   ReadLabel();
6755   m_organism->GetPhenotype().SetMateSelectID( GetLabel().AsInt(NUM_NOPS) );
6756 
6757   // Proceed as normal with the rest of mate selection.
6758   m_organism->GetPhenotype().SetDivideSex(true);
6759   m_organism->GetPhenotype().SetCrossNum(1);
6760   return Inst_HeadDivide(ctx);
6761 }
6762 
Inst_HeadDivide1(cAvidaContext & ctx)6763 bool cHardwareCPU::Inst_HeadDivide1(cAvidaContext& ctx)  { return Inst_HeadDivideMut(ctx, 1); }
Inst_HeadDivide2(cAvidaContext & ctx)6764 bool cHardwareCPU::Inst_HeadDivide2(cAvidaContext& ctx)  { return Inst_HeadDivideMut(ctx, 2); }
Inst_HeadDivide3(cAvidaContext & ctx)6765 bool cHardwareCPU::Inst_HeadDivide3(cAvidaContext& ctx)  { return Inst_HeadDivideMut(ctx, 3); }
Inst_HeadDivide4(cAvidaContext & ctx)6766 bool cHardwareCPU::Inst_HeadDivide4(cAvidaContext& ctx)  { return Inst_HeadDivideMut(ctx, 4); }
Inst_HeadDivide5(cAvidaContext & ctx)6767 bool cHardwareCPU::Inst_HeadDivide5(cAvidaContext& ctx)  { return Inst_HeadDivideMut(ctx, 5); }
Inst_HeadDivide6(cAvidaContext & ctx)6768 bool cHardwareCPU::Inst_HeadDivide6(cAvidaContext& ctx)  { return Inst_HeadDivideMut(ctx, 6); }
Inst_HeadDivide7(cAvidaContext & ctx)6769 bool cHardwareCPU::Inst_HeadDivide7(cAvidaContext& ctx)  { return Inst_HeadDivideMut(ctx, 7); }
Inst_HeadDivide8(cAvidaContext & ctx)6770 bool cHardwareCPU::Inst_HeadDivide8(cAvidaContext& ctx)  { return Inst_HeadDivideMut(ctx, 8); }
Inst_HeadDivide9(cAvidaContext & ctx)6771 bool cHardwareCPU::Inst_HeadDivide9(cAvidaContext& ctx)  { return Inst_HeadDivideMut(ctx, 9); }
Inst_HeadDivide10(cAvidaContext & ctx)6772 bool cHardwareCPU::Inst_HeadDivide10(cAvidaContext& ctx)  { return Inst_HeadDivideMut(ctx, 10); }
Inst_HeadDivide16(cAvidaContext & ctx)6773 bool cHardwareCPU::Inst_HeadDivide16(cAvidaContext& ctx)  { return Inst_HeadDivideMut(ctx, 16); }
Inst_HeadDivide32(cAvidaContext & ctx)6774 bool cHardwareCPU::Inst_HeadDivide32(cAvidaContext& ctx)  { return Inst_HeadDivideMut(ctx, 32); }
Inst_HeadDivide50(cAvidaContext & ctx)6775 bool cHardwareCPU::Inst_HeadDivide50(cAvidaContext& ctx)  { return Inst_HeadDivideMut(ctx, 50); }
Inst_HeadDivide100(cAvidaContext & ctx)6776 bool cHardwareCPU::Inst_HeadDivide100(cAvidaContext& ctx)  { return Inst_HeadDivideMut(ctx, 100); }
Inst_HeadDivide500(cAvidaContext & ctx)6777 bool cHardwareCPU::Inst_HeadDivide500(cAvidaContext& ctx)  { return Inst_HeadDivideMut(ctx, 500); }
Inst_HeadDivide1000(cAvidaContext & ctx)6778 bool cHardwareCPU::Inst_HeadDivide1000(cAvidaContext& ctx)  { return Inst_HeadDivideMut(ctx, 1000); }
Inst_HeadDivide5000(cAvidaContext & ctx)6779 bool cHardwareCPU::Inst_HeadDivide5000(cAvidaContext& ctx)  { return Inst_HeadDivideMut(ctx, 5000); }
Inst_HeadDivide10000(cAvidaContext & ctx)6780 bool cHardwareCPU::Inst_HeadDivide10000(cAvidaContext& ctx)  { return Inst_HeadDivideMut(ctx, 10000); }
Inst_HeadDivide50000(cAvidaContext & ctx)6781 bool cHardwareCPU::Inst_HeadDivide50000(cAvidaContext& ctx)  { return Inst_HeadDivideMut(ctx, 50000); }
Inst_HeadDivide0_5(cAvidaContext & ctx)6782 bool cHardwareCPU::Inst_HeadDivide0_5(cAvidaContext& ctx)  { return Inst_HeadDivideMut(ctx, 0.5); }
Inst_HeadDivide0_1(cAvidaContext & ctx)6783 bool cHardwareCPU::Inst_HeadDivide0_1(cAvidaContext& ctx)  { return Inst_HeadDivideMut(ctx, 0.1); }
Inst_HeadDivide0_05(cAvidaContext & ctx)6784 bool cHardwareCPU::Inst_HeadDivide0_05(cAvidaContext& ctx)  { return Inst_HeadDivideMut(ctx, 0.05); }
Inst_HeadDivide0_01(cAvidaContext & ctx)6785 bool cHardwareCPU::Inst_HeadDivide0_01(cAvidaContext& ctx)  { return Inst_HeadDivideMut(ctx, 0.01); }
Inst_HeadDivide0_001(cAvidaContext & ctx)6786 bool cHardwareCPU::Inst_HeadDivide0_001(cAvidaContext& ctx)  { return Inst_HeadDivideMut(ctx, 0.001); }
6787 
Inst_HeadRead(cAvidaContext & ctx)6788 bool cHardwareCPU::Inst_HeadRead(cAvidaContext& ctx)
6789 {
6790   const int dst = REG_BX;
6791 
6792   const int head_id = FindModifiedHead(nHardware::HEAD_READ);
6793   getHead(head_id).Adjust();
6794 
6795   // Mutations only occur on the read, for the moment.
6796   int read_inst = 0;
6797   if (m_organism->TestCopyMut(ctx)) {
6798     read_inst = m_inst_set->GetRandomInst(ctx).GetOp();
6799   } else {
6800     read_inst = getHead(head_id).GetInst().GetOp();
6801   }
6802   GetRegister(dst) = read_inst;
6803   ReadInst(read_inst);
6804 
6805   if (m_slip_read_head && m_organism->TestCopySlip(ctx)) {
6806     getHead(head_id).Set(ctx.GetRandom().GetInt(m_memory.GetSize()));
6807   }
6808 
6809   getHead(head_id).Advance();
6810   return true;
6811 }
6812 
Inst_HeadWrite(cAvidaContext & ctx)6813 bool cHardwareCPU::Inst_HeadWrite(cAvidaContext& ctx)
6814 {
6815   const int src = REG_BX;
6816   const int head_id = FindModifiedHead(nHardware::HEAD_WRITE);
6817   cHeadCPU& active_head = getHead(head_id);
6818 
6819   active_head.Adjust();
6820 
6821   int value = GetRegister(src);
6822   if (value < 0 || value >= m_inst_set->GetSize()) value = 0;
6823 
6824   active_head.SetInst(cInstruction(value));
6825   active_head.SetFlagCopied();
6826 
6827   if (m_organism->TestCopyIns(ctx)) active_head.InsertInst(m_inst_set->GetRandomInst(ctx));
6828   if (m_organism->TestCopyDel(ctx)) active_head.RemoveInst();
6829   if (m_organism->TestCopyUniform(ctx)) doUniformCopyMutation(ctx, active_head);
6830   if (!m_slip_read_head && m_organism->TestCopySlip(ctx)) {
6831     doSlipMutation(ctx, m_memory, active_head.GetPosition());
6832   }
6833 
6834   // Advance the head after write...
6835   active_head.Advance();
6836 
6837   return true;
6838 }
6839 
Inst_HeadCopy(cAvidaContext & ctx)6840 bool cHardwareCPU::Inst_HeadCopy(cAvidaContext& ctx)
6841 {
6842   // For the moment, this cannot be nop-modified.
6843   cHeadCPU& read_head = getHead(nHardware::HEAD_READ);
6844   cHeadCPU& write_head = getHead(nHardware::HEAD_WRITE);
6845 
6846   read_head.Adjust();
6847   write_head.Adjust();
6848 
6849   // Do mutations.
6850   cInstruction read_inst = read_head.GetInst();
6851   ReadInst(read_inst.GetOp());
6852 
6853   //checkNoMutList is for head to head kaboom experiments
6854   if (m_organism->TestCopyMut(ctx) && !(checkNoMutList(read_head))) {
6855     read_inst = m_inst_set->GetRandomInst(ctx);
6856     write_head.SetFlagMutated();
6857     write_head.SetFlagCopyMut();
6858   }
6859 
6860   write_head.SetInst(read_inst);
6861   write_head.SetFlagCopied();  // Set the copied flag...
6862 
6863   if (m_organism->TestCopyIns(ctx)) write_head.InsertInst(m_inst_set->GetRandomInst(ctx));
6864   if (m_organism->TestCopyDel(ctx)) write_head.RemoveInst();
6865   if (m_organism->TestCopyUniform(ctx)) doUniformCopyMutation(ctx, write_head);
6866   if (m_organism->TestCopySlip(ctx)) {
6867     if (m_slip_read_head) {
6868       read_head.Set(ctx.GetRandom().GetInt(m_memory.GetSize()));
6869     } else {
6870       doSlipMutation(ctx, m_memory, write_head.GetPosition());
6871     }
6872   }
6873 
6874   read_head.Advance();
6875   write_head.Advance();
6876   return true;
6877 }
6878 
HeadCopy_ErrorCorrect(cAvidaContext & ctx,double reduction)6879 bool cHardwareCPU::HeadCopy_ErrorCorrect(cAvidaContext& ctx, double reduction)
6880 {
6881   // For the moment, this cannot be nop-modified.
6882   cHeadCPU & read_head = getHead(nHardware::HEAD_READ);
6883   cHeadCPU & write_head = getHead(nHardware::HEAD_WRITE);
6884 
6885   read_head.Adjust();
6886   write_head.Adjust();
6887 
6888   // Do mutations.
6889   cInstruction read_inst = read_head.GetInst();
6890   ReadInst(read_inst.GetOp());
6891   //checkNoMutList for head to head kaboom experiments
6892   if ( ctx.GetRandom().P(m_organism->GetCopyMutProb() / reduction) && !(checkNoMutList(read_head))) {
6893     read_inst = m_inst_set->GetRandomInst(ctx);
6894     write_head.SetFlagMutated();
6895     write_head.SetFlagCopyMut();
6896   }
6897 
6898   write_head.SetInst(read_inst);
6899   write_head.SetFlagCopied();  // Set the copied flag...
6900 
6901   if (ctx.GetRandom().P(m_organism->GetCopyInsProb() / reduction)) write_head.InsertInst(m_inst_set->GetRandomInst(ctx));
6902   if (ctx.GetRandom().P(m_organism->GetCopyDelProb() / reduction)) write_head.RemoveInst();
6903   if (ctx.GetRandom().P(m_organism->GetCopyUniformProb() / reduction)) doUniformCopyMutation(ctx, write_head);
6904   if (ctx.GetRandom().P(m_organism->GetCopySlipProb() / reduction)) {
6905     if (m_slip_read_head) {
6906       read_head.Set(ctx.GetRandom().GetInt(m_memory.GetSize()));
6907     } else {
6908       doSlipMutation(ctx, m_memory, write_head.GetPosition());
6909     }
6910   }
6911 
6912   read_head.Advance();
6913   write_head.Advance();
6914   return true;
6915 }
6916 
Inst_HeadCopy2(cAvidaContext & ctx)6917 bool cHardwareCPU::Inst_HeadCopy2(cAvidaContext& ctx)  { return HeadCopy_ErrorCorrect(ctx, 2); }
Inst_HeadCopy3(cAvidaContext & ctx)6918 bool cHardwareCPU::Inst_HeadCopy3(cAvidaContext& ctx)  { return HeadCopy_ErrorCorrect(ctx, 3); }
Inst_HeadCopy4(cAvidaContext & ctx)6919 bool cHardwareCPU::Inst_HeadCopy4(cAvidaContext& ctx)  { return HeadCopy_ErrorCorrect(ctx, 4); }
Inst_HeadCopy5(cAvidaContext & ctx)6920 bool cHardwareCPU::Inst_HeadCopy5(cAvidaContext& ctx)  { return HeadCopy_ErrorCorrect(ctx, 5); }
Inst_HeadCopy6(cAvidaContext & ctx)6921 bool cHardwareCPU::Inst_HeadCopy6(cAvidaContext& ctx)  { return HeadCopy_ErrorCorrect(ctx, 6); }
Inst_HeadCopy7(cAvidaContext & ctx)6922 bool cHardwareCPU::Inst_HeadCopy7(cAvidaContext& ctx)  { return HeadCopy_ErrorCorrect(ctx, 7); }
Inst_HeadCopy8(cAvidaContext & ctx)6923 bool cHardwareCPU::Inst_HeadCopy8(cAvidaContext& ctx)  { return HeadCopy_ErrorCorrect(ctx, 8); }
Inst_HeadCopy9(cAvidaContext & ctx)6924 bool cHardwareCPU::Inst_HeadCopy9(cAvidaContext& ctx)  { return HeadCopy_ErrorCorrect(ctx, 9); }
Inst_HeadCopy10(cAvidaContext & ctx)6925 bool cHardwareCPU::Inst_HeadCopy10(cAvidaContext& ctx) { return HeadCopy_ErrorCorrect(ctx, 10); }
6926 
Inst_HeadSearch(cAvidaContext & ctx)6927 bool cHardwareCPU::Inst_HeadSearch(cAvidaContext& ctx)
6928 {
6929   ReadLabel();
6930   GetLabel().Rotate(1, NUM_NOPS);
6931   cHeadCPU found_pos = FindLabel(0);
6932   const int search_size = found_pos.GetPosition() - getIP().GetPosition();
6933   GetRegister(REG_BX) = search_size;
6934   GetRegister(REG_CX) = GetLabel().GetSize();
6935   getHead(nHardware::HEAD_FLOW).Set(found_pos);
6936   getHead(nHardware::HEAD_FLOW).Advance();
6937   return true;
6938 }
6939 
Inst_HeadSearchDirect(cAvidaContext & ctx)6940 bool cHardwareCPU::Inst_HeadSearchDirect(cAvidaContext& ctx)
6941 {
6942   ReadLabel();
6943   cHeadCPU found_pos = FindLabel(1);
6944   const int search_size = found_pos.GetPosition() - getIP().GetPosition();
6945   GetRegister(REG_BX) = search_size;
6946   GetRegister(REG_CX) = GetLabel().GetSize();
6947   getHead(nHardware::HEAD_FLOW).Set(found_pos);
6948   getHead(nHardware::HEAD_FLOW).Advance();
6949   return true;
6950 }
6951 
Inst_SetFlow(cAvidaContext & ctx)6952 bool cHardwareCPU::Inst_SetFlow(cAvidaContext& ctx)
6953 {
6954   const int reg_used = FindModifiedRegister(REG_CX);
6955   getHead(nHardware::HEAD_FLOW).Set(GetRegister(reg_used));
6956   return true;
6957 }
6958 
6959 
6960 /* Execute the next instruction if the organism's energy level is low */
Inst_IfEnergyLow(cAvidaContext & ctx)6961 bool cHardwareCPU::Inst_IfEnergyLow(cAvidaContext& ctx)
6962 {
6963   if (m_organism->GetCellID() < 0) {
6964     return false;
6965   }
6966 
6967   // Note: these instructions should probably also make sure the returned energy level is not -1.
6968   if (m_organism->GetPhenotype().GetDiscreteEnergyLevel() != cPhenotype::ENERGY_LEVEL_LOW) {
6969     getIP().Advance();
6970   }
6971 
6972   return true;
6973 
6974 } //End Inst_IfEnergyLow()
6975 
6976 
6977 /* Execute the next instruction if the organism's energy level is not low */
Inst_IfEnergyNotLow(cAvidaContext & ctx)6978 bool cHardwareCPU::Inst_IfEnergyNotLow(cAvidaContext& ctx)
6979 {
6980   if (m_organism->GetCellID() < 0) {
6981     return false;
6982   }
6983 
6984   if (m_organism->GetPhenotype().GetDiscreteEnergyLevel() == cPhenotype::ENERGY_LEVEL_LOW) {
6985     getIP().Advance();
6986   }
6987 
6988   return true;
6989 
6990 } //End Inst_IfEnergyNotLow()
6991 
6992 
6993 /* Execute the next instruction if the faced organism's energy level is low */
Inst_IfFacedEnergyLow(cAvidaContext & ctx)6994 bool cHardwareCPU::Inst_IfFacedEnergyLow(cAvidaContext& ctx)
6995 {
6996   if (m_organism->GetCellID() < 0) {
6997     return false;
6998   }
6999 
7000   // Get faced neighbor
7001   cOrganism * neighbor = m_organism->GetNeighbor();
7002 
7003   if ( (neighbor != NULL) && (!neighbor->IsDead()) ){
7004     // Note: these instructions should probably also make sure the returned energy level is not -1.
7005     if (neighbor->GetPhenotype().GetDiscreteEnergyLevel() != cPhenotype::ENERGY_LEVEL_LOW) {
7006       getIP().Advance();
7007     }
7008   }
7009 
7010   return true;
7011 
7012 } //End Inst_IfFacedEnergyLow()
7013 
7014 
7015 /* Execute the next instruction if the faced organism's energy level is low */
Inst_IfFacedEnergyNotLow(cAvidaContext & ctx)7016 bool cHardwareCPU::Inst_IfFacedEnergyNotLow(cAvidaContext& ctx)
7017 {
7018   if (m_organism->GetCellID() < 0) {
7019     return false;
7020   }
7021 
7022   // Get faced neighbor
7023   cOrganism * neighbor = m_organism->GetNeighbor();
7024 
7025   if ( (neighbor != NULL) && (!neighbor->IsDead()) ) {
7026     // Note: these instructions should probably also make sure the returned energy level is not -1.
7027     if (neighbor->GetPhenotype().GetDiscreteEnergyLevel() == cPhenotype::ENERGY_LEVEL_LOW) {
7028       getIP().Advance();
7029     }
7030   }
7031 
7032   return true;
7033 
7034 } //End Inst_IfFacedEnergyNotLow()
7035 
7036 
7037 /* Execute the next instruction if the organism's energy level is high */
Inst_IfEnergyHigh(cAvidaContext & ctx)7038 bool cHardwareCPU::Inst_IfEnergyHigh(cAvidaContext& ctx)
7039 {
7040   if (m_organism->GetCellID() < 0) {
7041     return false;
7042   }
7043 
7044   if (m_organism->GetPhenotype().GetDiscreteEnergyLevel() != cPhenotype::ENERGY_LEVEL_HIGH) {
7045     getIP().Advance();
7046   }
7047 
7048   return true;
7049 
7050 } //End Inst_IfEnergyHigh()
7051 
7052 
7053 /* Execute the next instruction if the organism's energy level is not high */
Inst_IfEnergyNotHigh(cAvidaContext & ctx)7054 bool cHardwareCPU::Inst_IfEnergyNotHigh(cAvidaContext& ctx)
7055 {
7056   if (m_organism->GetCellID() < 0) {
7057     return false;
7058   }
7059 
7060   if (m_organism->GetPhenotype().GetDiscreteEnergyLevel() == cPhenotype::ENERGY_LEVEL_HIGH) {
7061     getIP().Advance();
7062   }
7063 
7064   return true;
7065 
7066 } //End Inst_IfEnergyNotHigh()
7067 
7068 
7069 /* Execute the next instruction if the faced organism's energy level is high */
Inst_IfFacedEnergyHigh(cAvidaContext & ctx)7070 bool cHardwareCPU::Inst_IfFacedEnergyHigh(cAvidaContext& ctx)
7071 {
7072   if (m_organism->GetCellID() < 0) {
7073     return false;
7074   }
7075 
7076   // Get faced neighbor
7077   cOrganism * neighbor = m_organism->GetNeighbor();
7078 
7079   if ( (neighbor != NULL) && (!neighbor->IsDead()) ) {
7080     // Note: these instructions should probably also make sure the returned energy level is not -1.
7081     if (neighbor->GetPhenotype().GetDiscreteEnergyLevel() != cPhenotype::ENERGY_LEVEL_HIGH) {
7082       getIP().Advance();
7083     }
7084   }
7085 
7086   return true;
7087 
7088 } //End Inst_IfFacedEnergyHigh()
7089 
7090 
7091 /* Execute the next instruction if the faced organism's energy level is not high */
Inst_IfFacedEnergyNotHigh(cAvidaContext & ctx)7092 bool cHardwareCPU::Inst_IfFacedEnergyNotHigh(cAvidaContext& ctx)
7093 {
7094   if (m_organism->GetCellID() < 0) {
7095     return false;
7096   }
7097 
7098   // Get faced neighbor
7099   cOrganism * neighbor = m_organism->GetNeighbor();
7100 
7101   if ( (neighbor != NULL) && (!neighbor->IsDead()) ) {
7102     // Note: these instructions should probably also make sure the returned energy level is not -1.
7103     if (neighbor->GetPhenotype().GetDiscreteEnergyLevel() == cPhenotype::ENERGY_LEVEL_HIGH) {
7104       getIP().Advance();
7105     }
7106   }
7107 
7108   return true;
7109 
7110 } //End Inst_IfFacedEnergyNotHigh()
7111 
7112 
7113 /* Execute the next instruction if the organism's energy level is medium */
Inst_IfEnergyMed(cAvidaContext & ctx)7114 bool cHardwareCPU::Inst_IfEnergyMed(cAvidaContext& ctx)
7115 {
7116   if (m_organism->GetCellID() < 0) {
7117     return false;
7118   }
7119 
7120   if (m_organism->GetPhenotype().GetDiscreteEnergyLevel() != cPhenotype::ENERGY_LEVEL_MEDIUM) {
7121     getIP().Advance();
7122   }
7123 
7124   return true;
7125 
7126 } //End Inst_IfEnergyMed()
7127 
7128 
7129 /* Execute the next instruction if the faced organism's energy level is medium */
Inst_IfFacedEnergyMed(cAvidaContext & ctx)7130 bool cHardwareCPU::Inst_IfFacedEnergyMed(cAvidaContext& ctx)
7131 {
7132   if (m_organism->GetCellID() < 0) {
7133     return false;
7134   }
7135 
7136   // Get faced neighbor
7137   cOrganism * neighbor = m_organism->GetNeighbor();
7138 
7139   if ( (neighbor != NULL) && (!neighbor->IsDead()) ) {
7140     // Note: these instructions should probably also make sure the returned energy level is not -1.
7141     if (neighbor->GetPhenotype().GetDiscreteEnergyLevel() != cPhenotype::ENERGY_LEVEL_MEDIUM) {
7142       getIP().Advance();
7143     }
7144   }
7145 
7146   return true;
7147 
7148 } //End Inst_IfFacedEnergyMed()
7149 
7150 
7151 /* Execute the next instruction if the faced organism has less energy */
Inst_IfFacedEnergyLess(cAvidaContext & ctx)7152 bool cHardwareCPU::Inst_IfFacedEnergyLess(cAvidaContext& ctx)
7153 {
7154   if (m_organism->GetCellID() < 0) {
7155     return false;
7156   }
7157 
7158   // Get faced neighbor
7159   cOrganism * neighbor = m_organism->GetNeighbor();
7160 
7161   if ( (neighbor != NULL) && (!neighbor->IsDead()) ) {
7162     const double neighbor_energy = neighbor->GetPhenotype().GetStoredEnergy();
7163     const double my_energy = m_organism->GetPhenotype().GetStoredEnergy();
7164     const double epsilon = m_world->GetConfig().ENERGY_COMPARISON_EPSILON.Get();
7165 
7166     if (neighbor_energy >= (my_energy * (1 - epsilon))) {
7167       getIP().Advance();
7168     }
7169   }
7170 
7171   return true;
7172 
7173 } //End Inst_IfFacedEnergyLess()
7174 
7175 
7176 /* Execute the next instruction if the faced organism has more energy */
Inst_IfFacedEnergyMore(cAvidaContext & ctx)7177 bool cHardwareCPU::Inst_IfFacedEnergyMore(cAvidaContext& ctx)
7178 {
7179   if (m_organism->GetCellID() < 0) {
7180     return false;
7181   }
7182 
7183   // Get faced neighbor
7184   cOrganism * neighbor = m_organism->GetNeighbor();
7185 
7186   if ( (neighbor != NULL) && (!neighbor->IsDead()) ) {
7187     const double neighbor_energy = neighbor->GetPhenotype().GetStoredEnergy();
7188     const double my_energy = m_organism->GetPhenotype().GetStoredEnergy();
7189     const double epsilon = m_world->GetConfig().ENERGY_COMPARISON_EPSILON.Get();
7190 
7191     if (neighbor_energy <= (my_energy * (1 + epsilon))) {
7192       getIP().Advance();
7193     }
7194   }
7195 
7196   return true;
7197 
7198 } //End Inst_IfFacedEnergyMore()
7199 
7200 
7201 /* Execute the next instruction if the organism has received energy */
Inst_IfEnergyInBuffer(cAvidaContext & ctx)7202 bool cHardwareCPU::Inst_IfEnergyInBuffer(cAvidaContext& ctx)
7203 {
7204   if (m_organism->GetCellID() < 0) {
7205     return false;
7206   }
7207 
7208   if (m_organism->GetPhenotype().GetEnergyInBufferAmount() == 0) {
7209     getIP().Advance();
7210   }
7211 
7212   return true;
7213 
7214 } //End Inst_IfEnergyInBuffer()
7215 
7216 
7217 /* Execute the next instruction if the organism has not received energy */
Inst_IfEnergyNotInBuffer(cAvidaContext & ctx)7218 bool cHardwareCPU::Inst_IfEnergyNotInBuffer(cAvidaContext& ctx)
7219 {
7220   if (m_organism->GetCellID() < 0) {
7221     return false;
7222   }
7223 
7224   if (m_organism->GetPhenotype().GetEnergyInBufferAmount() > 0) {
7225     getIP().Advance();
7226   }
7227 
7228   return true;
7229 
7230 } //End Inst_IfEnergyNotInBuffer()
7231 
7232 
Inst_GetEnergyLevel(cAvidaContext & ctx)7233 bool cHardwareCPU::Inst_GetEnergyLevel(cAvidaContext& ctx)
7234 {
7235   if (m_organism->GetCellID() < 0) {
7236     return false;
7237   }
7238 
7239   const int reg = FindModifiedRegister(REG_BX);
7240   GetRegister(reg) = (int) floor(m_organism->GetPhenotype().GetStoredEnergy());
7241 
7242   return true;
7243 
7244 } //End Inst_GetEnergyLevel()
7245 
7246 
Inst_GetFacedEnergyLevel(cAvidaContext & ctx)7247 bool cHardwareCPU::Inst_GetFacedEnergyLevel(cAvidaContext& ctx)
7248 {
7249   if (m_organism->GetCellID() < 0) {
7250     return false;
7251   }
7252 
7253   cOrganism * neighbor = m_organism->GetNeighbor();
7254 
7255   if ( (neighbor == NULL) || (neighbor->IsDead()) ) {
7256     return false;
7257   }
7258 
7259   const int reg = FindModifiedRegister(REG_BX);
7260   GetRegister(reg) = (int) floor(neighbor->GetPhenotype().GetStoredEnergy());
7261 
7262   return true;
7263 
7264 } //End Inst_GetFacedEnergyLevel()
7265 
7266 
Inst_IfFacedEnergyRequestOn(cAvidaContext & ctx)7267 bool cHardwareCPU::Inst_IfFacedEnergyRequestOn(cAvidaContext& ctx)
7268 {
7269   if (m_organism->GetCellID() < 0) {
7270     return false;
7271   }
7272 
7273   cOrganism * neighbor = m_organism->GetNeighbor();
7274 
7275   if ( (neighbor == NULL) || (neighbor->IsDead()) ) {
7276     return false;
7277   }
7278 
7279   if (neighbor->GetPhenotype().IsEnergyRequestor() == false) {
7280     getIP().Advance();
7281   }
7282 
7283   return true;
7284 
7285 } //End Inst_IfFacedEnergyRequestOn()
7286 
Inst_IfFacedEnergyRequestOff(cAvidaContext & ctx)7287 bool cHardwareCPU::Inst_IfFacedEnergyRequestOff(cAvidaContext& ctx)
7288 {
7289   if (m_organism->GetCellID() < 0) {
7290     return false;
7291   }
7292 
7293   cOrganism * neighbor = m_organism->GetNeighbor();
7294 
7295   if ( (neighbor == NULL) || (neighbor->IsDead()) ) {
7296     return false;
7297   }
7298 
7299   if (neighbor->GetPhenotype().IsEnergyRequestor() == true) {
7300     getIP().Advance();
7301   }
7302 
7303   return true;
7304 
7305 } //End Inst_IfFacedEnergyRequestOff()
7306 
7307 
Inst_GetEnergyRequestStatus(cAvidaContext & ctx)7308 bool cHardwareCPU::Inst_GetEnergyRequestStatus(cAvidaContext& ctx)
7309 {
7310   if (m_organism->GetCellID() < 0) {
7311     return false;
7312   }
7313 
7314   const int reg = FindModifiedRegister(REG_BX);
7315   int status = 0;
7316 
7317   if (m_organism->GetPhenotype().IsEnergyRequestor() == true) {
7318     status = 1;
7319   }
7320 
7321   GetRegister(reg) = status;
7322 
7323   return true;
7324 
7325 } //End Inst_GetEnergyRequestStatus()
7326 
7327 
Inst_GetFacedEnergyRequestStatus(cAvidaContext & ctx)7328 bool cHardwareCPU::Inst_GetFacedEnergyRequestStatus(cAvidaContext& ctx)
7329 {
7330   if (m_organism->GetCellID() < 0) return false;
7331 
7332   cOrganism * neighbor = m_organism->GetNeighbor();
7333 
7334   if ( (neighbor == NULL) || (neighbor->IsDead()) ) {
7335     return false;
7336   }
7337 
7338   const int reg = FindModifiedRegister(REG_BX);
7339   int status = 0;
7340 
7341   if (neighbor->GetPhenotype().IsEnergyRequestor() == true) {
7342     status = 1;
7343   }
7344 
7345   GetRegister(reg) = status;
7346 
7347   return true;
7348 
7349 } //End Inst_GetFacedEnergyRequestStatus()
7350 
7351 
Inst_Sleep(cAvidaContext & ctx)7352 bool cHardwareCPU::Inst_Sleep(cAvidaContext& ctx)
7353 {
7354   m_organism->SetSleeping(false);  //this instruction get executed at the end of a sleep cycle
7355 
7356   cPhenotype& phenotype = m_organism->GetPhenotype();
7357   if (m_world->GetConfig().APPLY_ENERGY_METHOD.Get() == 2) {
7358     phenotype.RefreshEnergy();
7359     phenotype.ApplyToEnergyStore();
7360     double newMerit = phenotype.ConvertEnergyToMerit(phenotype.GetStoredEnergy() * phenotype.GetEnergyUsageRatio());
7361     m_organism->UpdateMerit(newMerit);
7362   }
7363 
7364   return true;
7365 }
7366 
Inst_GetUpdate(cAvidaContext & ctx)7367 bool cHardwareCPU::Inst_GetUpdate(cAvidaContext& ctx)
7368 {
7369   const int reg_used = FindModifiedRegister(REG_BX);
7370   GetRegister(reg_used) = m_world->GetStats().GetUpdate();
7371 
7372   return true;
7373 }
7374 
7375 
7376 /*! This method places the calling organism's x-y coordinates in ?BX? and ?++BX?.
7377 
7378  Note that this method *will not work* from within the test CPU, so we have to guard
7379  against that.
7380  */
Inst_GetCellPosition(cAvidaContext & ctx)7381 bool cHardwareCPU::Inst_GetCellPosition(cAvidaContext& ctx)
7382 {
7383   int x = m_organism->GetOrgInterface().GetCellXPosition();
7384   int y = m_organism->GetOrgInterface().GetCellYPosition();
7385   // Fail if we're running in the test CPU.
7386   if (x == -1 || y == -1) return false;
7387 
7388   const int xreg = FindModifiedRegister(REG_BX);
7389   const int yreg = FindNextRegister(xreg);
7390   GetRegister(xreg) = x;
7391   GetRegister(yreg) = y;
7392 
7393   return true;
7394 }
7395 
7396 /*! This method places the calling organism's x coordinate in ?BX?.
7397 
7398  Note that this method *will not work* from within the test CPU, so we have to guard
7399  against that.
7400  */
Inst_GetCellPositionX(cAvidaContext & ctx)7401 bool cHardwareCPU::Inst_GetCellPositionX(cAvidaContext& ctx)
7402 {
7403   int x = m_organism->GetOrgInterface().GetCellXPosition();
7404   // Fail if we're running in the test CPU.
7405   if (x == -1) return false;
7406 
7407   const int xreg = FindModifiedRegister(REG_BX);
7408   GetRegister(xreg) = x;
7409 
7410   return true;
7411 }
7412 
7413 /*! This method places the calling organism's y coordinates in ?BX?.
7414 
7415  Note that this method *will not work* from within the test CPU, so we have to guard
7416  against that.
7417  */
Inst_GetCellPositionY(cAvidaContext & ctx)7418 bool cHardwareCPU::Inst_GetCellPositionY(cAvidaContext& ctx)
7419 {
7420   int y = m_organism->GetOrgInterface().GetCellYPosition();
7421   // Fail if we're running in the test CPU.
7422   if (y == -1) return false;
7423 
7424   const int yreg = FindModifiedRegister(REG_BX);
7425   GetRegister(yreg) = y;
7426 
7427   return true;
7428 }
7429 
Inst_GetDistanceFromDiagonal(cAvidaContext & ctx)7430 bool cHardwareCPU::Inst_GetDistanceFromDiagonal(cAvidaContext& ctx)
7431 {
7432   int absolute_cell_ID = m_organism->GetOrgInterface().GetCellID();
7433   int deme_id = m_organism->GetOrgInterface().GetDemeID();
7434   // Fail if we're running in the test CPU.
7435   if ((deme_id < 0) || (absolute_cell_ID < 0)) return false;
7436 
7437   std::pair<int, int> pos = m_world->GetPopulation().GetDeme(deme_id).GetCellPosition(absolute_cell_ID);
7438   const int reg = FindModifiedRegister(REG_BX);
7439 
7440   if (pos.first > pos.second) {
7441     GetRegister(reg) = (int)ceil((pos.first - pos.second)/2.0);
7442   } else {
7443     GetRegister(reg) = (int)floor((pos.first - pos.second)/2.0);
7444   }
7445   //  std::cerr<<"x = "<<pos.first<<"  y = "<<pos.second<<"  ans = "<<GetRegister(reg)<<std::endl;
7446 
7447   return true;
7448 }
7449 
Inst_GetDirectionOffNorth(cAvidaContext & ctx)7450 bool cHardwareCPU::Inst_GetDirectionOffNorth(cAvidaContext& ctx) {
7451   const int out_reg = FindModifiedRegister(REG_BX);
7452   GetRegister(out_reg) = m_organism->GetFacedDir();
7453   return true;
7454 }
7455 
Inst_GetNortherly(cAvidaContext & ctx)7456 bool cHardwareCPU::Inst_GetNortherly(cAvidaContext& ctx) {
7457   const int out_reg = FindModifiedRegister(REG_BX);
7458   GetRegister(out_reg) = m_organism->GetNortherly();
7459   return true;
7460 }
7461 
Inst_GetEasterly(cAvidaContext & ctx)7462 bool cHardwareCPU::Inst_GetEasterly(cAvidaContext& ctx) {
7463   const int out_reg = FindModifiedRegister(REG_BX);
7464   GetRegister(out_reg) = m_organism->GetEasterly();
7465   return true;
7466 }
7467 
Inst_ZeroEasterly(cAvidaContext & ctx)7468 bool cHardwareCPU::Inst_ZeroEasterly(cAvidaContext& ctx) {
7469   m_organism->ClearEasterly();
7470   return true;
7471 }
7472 
Inst_ZeroNortherly(cAvidaContext & ctx)7473 bool cHardwareCPU::Inst_ZeroNortherly(cAvidaContext& ctx) {
7474   m_organism->ClearNortherly();
7475   return true;
7476 }
7477 
7478 //// Promoter Model ////
7479 
Inst_Promoter(cAvidaContext & ctx)7480 bool cHardwareCPU::Inst_Promoter(cAvidaContext& ctx)
7481 {
7482   // Promoters don't do anything themselves
7483   return true;
7484 }
7485 
7486 // Move the instruction ptr to the next active promoter
Inst_Terminate(cAvidaContext & ctx)7487 bool cHardwareCPU::Inst_Terminate(cAvidaContext& ctx)
7488 {
7489   // Optionally,
7490   // Reset the thread.
7491   if (m_world->GetConfig().TERMINATION_RESETS.Get())
7492   {
7493     //const int write_head_pos = getHead(nHardware::HEAD_WRITE).GetPosition();
7494     //const int read_head_pos = getHead(nHardware::HEAD_READ).GetPosition();
7495     m_threads[m_cur_thread].Reset(this, m_threads[m_cur_thread].GetID());
7496     //getHead(nHardware::HEAD_WRITE).Set(write_head_pos);
7497     //getHead(nHardware::HEAD_READ).Set(read_head_pos);
7498 
7499     //Setting this makes it harder to do things. You have to be modular.
7500     m_organism->GetOrgInterface().ResetInputs(ctx);   // Re-randomize the inputs this organism sees
7501     m_organism->ClearInput();                         // Also clear their input buffers, or they can still claim
7502     // rewards for numbers no longer in their environment!
7503   }
7504 
7505   // Reset our count
7506   m_threads[m_cur_thread].ResetPromoterInstExecuted();
7507   m_advance_ip = false;
7508   const int reg_used = REG_BX; // register to put chosen promoter code in, for now always BX
7509 
7510   // Search for an active promoter
7511   int start_offset = m_promoter_offset;
7512   int start_index  = m_promoter_index;
7513 
7514   bool no_promoter_found = true;
7515   if ( m_promoters.GetSize() > 0 ) {
7516     while (true) {
7517       // If the next promoter is active, then break out
7518       NextPromoter();
7519       if (IsActivePromoter()) {
7520         no_promoter_found = false;
7521         break;
7522       }
7523 
7524       // If we just checked the promoter that we were originally on, then there
7525       // are no active promoters.
7526       if ( (start_offset == m_promoter_offset) && (start_index == m_promoter_index) ) break;
7527 
7528       // If we originally were not on a promoter, then stop once we check the
7529       // first promoter and an offset of zero
7530       if (start_index == -1) {
7531         start_index = 0;
7532       }
7533     }
7534   }
7535 
7536   if (no_promoter_found) {
7537     if ((m_world->GetConfig().NO_ACTIVE_PROMOTER_EFFECT.Get() == 0) || (m_world->GetConfig().NO_ACTIVE_PROMOTER_EFFECT.Get() == 2)) {
7538       // Set defaults for when no active promoter is found
7539       m_promoter_index = -1;
7540       getIP().Set(0);
7541       GetRegister(reg_used) = 0;
7542     }
7543     // Death to organisms that refuse to use promoters!
7544     else if (m_world->GetConfig().NO_ACTIVE_PROMOTER_EFFECT.Get() == 1) {
7545       m_organism->Die(ctx);
7546     } else {
7547       cout << "Unrecognized NO_ACTIVE_PROMOTER_EFFECT setting: " << m_world->GetConfig().NO_ACTIVE_PROMOTER_EFFECT.Get() << endl;
7548     }
7549   }
7550   else
7551   {
7552     // We found an active match, offset to just after it.
7553     // cHeadCPU will do the mod genome size for us
7554     getIP().Set(m_promoters[m_promoter_index].m_pos + 1);
7555 
7556     // Put its bit code in BX for the organism to have if option is set
7557     if ( m_world->GetConfig().PROMOTER_TO_REGISTER.Get() ) {
7558       GetRegister(reg_used) = m_promoters[m_promoter_index].m_bit_code;
7559     }
7560   }
7561 
7562   return true;
7563 }
7564 
7565 // Set a new regulation code (which is XOR'ed with ALL promoter codes).
Inst_Regulate(cAvidaContext & ctx)7566 bool cHardwareCPU::Inst_Regulate(cAvidaContext& ctx)
7567 {
7568   const int reg_used = FindModifiedRegister(REG_BX);
7569   int regulation_code = GetRegister(reg_used);
7570 
7571   for (int i=0; i< m_promoters.GetSize();i++) {
7572     m_promoters[i].m_regulation = regulation_code;
7573   }
7574 
7575   return true;
7576 }
7577 
7578 // Set a new regulation code, but only on a subset of promoters.
Inst_RegulateSpecificPromoters(cAvidaContext & ctx)7579 bool cHardwareCPU::Inst_RegulateSpecificPromoters(cAvidaContext& ctx)
7580 {
7581   const int reg_used = FindModifiedRegister(REG_BX);
7582   int regulation_code = GetRegister(reg_used);
7583 
7584   const int reg_promoter = FindModifiedRegister((reg_used+1) % NUM_REGISTERS);
7585   int regulation_promoter = GetRegister(reg_promoter);
7586 
7587   for (int i=0; i< m_promoters.GetSize();i++) {
7588     //Look for consensus bit matches over the length of the promoter code
7589     int test_p_code = m_promoters[i].m_bit_code;
7590     int test_r_code = regulation_promoter;
7591     int bit_count = 0;
7592     for (int j=0; j<m_world->GetConfig().PROMOTER_EXE_LENGTH.Get();j++) {
7593       if ((test_p_code & 1) == (test_r_code & 1)) bit_count++;
7594       test_p_code >>= 1;
7595       test_r_code >>= 1;
7596     }
7597     if (bit_count >= m_world->GetConfig().PROMOTER_EXE_LENGTH.Get() / 2) {
7598       m_promoters[i].m_regulation = regulation_code;
7599     }
7600   }
7601 
7602   return true;
7603 }
7604 
7605 
Inst_SenseRegulate(cAvidaContext & ctx)7606 bool cHardwareCPU::Inst_SenseRegulate(cAvidaContext& ctx)
7607 {
7608   unsigned int bits = 0;
7609   const tArray<double> & res_count = m_organism->GetOrgInterface().GetResources(ctx);
7610   assert (res_count.GetSize() != 0);
7611   for (int i=0; i<m_world->GetConfig().PROMOTER_CODE_SIZE.Get(); i++) {
7612     int b = i % res_count.GetSize();
7613     bits <<= 1;
7614     bits += (res_count[b] != 0);
7615   }
7616 
7617   for (int i=0; i< m_promoters.GetSize();i++) {
7618     m_promoters[i].m_regulation = bits;
7619   }
7620 
7621   return true;
7622 }
7623 
7624 // Create a number from inst bit codes
Do_Numberate(cAvidaContext & ctx,int num_bits)7625 bool cHardwareCPU::Do_Numberate(cAvidaContext& ctx, int num_bits)
7626 {
7627   const int reg_used = FindModifiedRegister(REG_BX);
7628 
7629   // advance the IP now, so that it rests on the beginning of our number
7630   getIP().Advance();
7631   m_advance_ip = false;
7632 
7633   int num = Numberate(getIP().GetPosition(), +1, num_bits);
7634   GetRegister(reg_used) = num;
7635 
7636   return true;
7637 }
7638 
7639 // Move to the next promoter.
NextPromoter()7640 void cHardwareCPU::NextPromoter()
7641 {
7642   // Move promoter index, rolling over if necessary
7643   m_promoter_index++;
7644   if (m_promoter_index == m_promoters.GetSize()) {
7645     m_promoter_index = 0;
7646 
7647     // Move offset, rolling over when there are not enough bits before we would have to wrap around left
7648     m_promoter_offset+=m_world->GetConfig().PROMOTER_EXE_LENGTH.Get();
7649     if (m_promoter_offset + m_world->GetConfig().PROMOTER_EXE_LENGTH.Get() > m_world->GetConfig().PROMOTER_CODE_SIZE.Get()) {
7650       m_promoter_offset = 0;
7651     }
7652   }
7653 }
7654 
7655 
7656 // Check whether the current promoter is active.
IsActivePromoter()7657 bool cHardwareCPU::IsActivePromoter()
7658 {
7659   assert( m_promoters.GetSize() != 0 );
7660   int count = 0;
7661   unsigned int code = m_promoters[m_promoter_index].GetRegulatedBitCode();
7662   for (int i=0; i<m_world->GetConfig().PROMOTER_EXE_LENGTH.Get(); i++) {
7663     int offset = m_promoter_offset + i;
7664     offset %= m_world->GetConfig().PROMOTER_CODE_SIZE.Get();
7665     int state = code >> offset;
7666     count += (state & 1);
7667   }
7668 
7669   return (count >= m_world->GetConfig().PROMOTER_EXE_THRESHOLD.Get());
7670 }
7671 
7672 // Construct a promoter bit code from instruction bit codes
Numberate(int _pos,int _dir,int _num_bits)7673 int cHardwareCPU::Numberate(int _pos, int _dir, int _num_bits)
7674 {
7675   int code_size = 0;
7676   unsigned int code = 0;
7677   unsigned int max_bits = sizeof(code) * 8;
7678   assert(_num_bits <= (int)max_bits);
7679   if (_num_bits == 0) _num_bits = max_bits;
7680 
7681   // Enforce a boundary, sometimes -1 can be passed for _pos
7682   int j = _pos + m_memory.GetSize();
7683   j %= m_memory.GetSize();
7684   assert(j >=0);
7685   assert(j < m_memory.GetSize());
7686   while (code_size < _num_bits) {
7687     unsigned int inst_code = (unsigned int) GetInstSet().GetInstructionCode(m_memory[j]);
7688     // shift bits in, one by one ... excuse the counter variable pun
7689     for (int code_on = 0; (code_size < _num_bits) && (code_on < m_world->GetConfig().INST_CODE_LENGTH.Get()); code_on++) {
7690       if (_dir < 0) {
7691         code >>= 1; // shift first so we don't go one too far at the end
7692         code += (1 << (_num_bits - 1)) * (inst_code & 1);
7693         inst_code >>= 1;
7694       } else {
7695         code <<= 1; // shift first so we don't go one too far at the end;
7696         code += (inst_code >> (m_world->GetConfig().INST_CODE_LENGTH.Get() - 1)) & 1;
7697         inst_code <<= 1;
7698       }
7699       code_size++;
7700     }
7701 
7702     // move back one inst
7703     j += m_memory.GetSize() + _dir;
7704     j %= m_memory.GetSize();
7705   }
7706 
7707   return code;
7708 }
7709 
7710 
7711 //// Copied from cHardwareExperimental -- @JEB
7712 static const unsigned int CONSENSUS = (sizeof(int) * 8) / 2;
7713 static const unsigned int CONSENSUS24 = 12;
7714 
BitCount(unsigned int value) const7715 inline unsigned int cHardwareCPU::BitCount(unsigned int value) const
7716 {
7717   const unsigned int w = value - ((value >> 1) & 0x55555555);
7718   const unsigned int x = (w & 0x33333333) + ((w >> 2) & 0x33333333);
7719   const unsigned int bit_count = ((x + (x >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
7720   return bit_count;
7721 }
7722 
Inst_BitConsensus(cAvidaContext & ctx)7723 bool cHardwareCPU::Inst_BitConsensus(cAvidaContext& ctx)
7724 {
7725   const int reg_used = FindModifiedRegister(REG_BX);
7726   const int op1 = FindModifiedNextRegister(reg_used);
7727   GetRegister(reg_used) = (BitCount(GetRegister(op1)) >= CONSENSUS) ? 1 : 0;
7728   return true;
7729 }
7730 
Inst_BitConsensus24(cAvidaContext & ctx)7731 bool cHardwareCPU::Inst_BitConsensus24(cAvidaContext& ctx)
7732 {
7733   const int reg_used = FindModifiedRegister(REG_BX);
7734   const int op1 = FindModifiedNextRegister(reg_used);
7735   GetRegister(reg_used) = (BitCount(GetRegister(op1) & MASK24) >= CONSENSUS24) ? 1 : 0;
7736   return true;
7737 }
7738 
Inst_IfConsensus(cAvidaContext & ctx)7739 bool cHardwareCPU::Inst_IfConsensus(cAvidaContext& ctx)
7740 {
7741   const int op1 = FindModifiedRegister(REG_BX);
7742   if (BitCount(GetRegister(op1)) <  CONSENSUS)  getIP().Advance();
7743   return true;
7744 }
7745 
Inst_IfConsensus24(cAvidaContext & ctx)7746 bool cHardwareCPU::Inst_IfConsensus24(cAvidaContext& ctx)
7747 {
7748   const int op1 = FindModifiedRegister(REG_BX);
7749   if (BitCount(GetRegister(op1) & MASK24) <  CONSENSUS24)  getIP().Advance();
7750   return true;
7751 }
7752 
Inst_IfLessConsensus(cAvidaContext & ctx)7753 bool cHardwareCPU::Inst_IfLessConsensus(cAvidaContext& ctx)
7754 {
7755   const int op1 = FindModifiedRegister(REG_BX);
7756   const int op2 = FindModifiedNextRegister(op1);
7757   if (BitCount(GetRegister(op1)) >=  BitCount(GetRegister(op2)))  getIP().Advance();
7758   return true;
7759 }
7760 
Inst_IfLessConsensus24(cAvidaContext & ctx)7761 bool cHardwareCPU::Inst_IfLessConsensus24(cAvidaContext& ctx)
7762 {
7763   const int op1 = FindModifiedRegister(REG_BX);
7764   const int op2 = FindModifiedNextRegister(op1);
7765   if (BitCount(GetRegister(op1) & MASK24) >=  BitCount(GetRegister(op2) & MASK24))  getIP().Advance();
7766   return true;
7767 }
7768 
7769 //// End copied from cHardwareExperimental
7770 
7771 
7772 /* Bit masking instructions */
7773 
7774 // masks sign bit in a register
Inst_MaskSignBit(cAvidaContext & ctx)7775 bool cHardwareCPU::Inst_MaskSignBit(cAvidaContext& ctx)
7776 {
7777   const int reg = FindModifiedRegister(REG_BX);
7778   GetRegister(reg) = GetRegister(reg) & MASK_SIGNBIT;
7779   return true;
7780 }
7781 
7782 // masks lower 16 bits in ?BX? register
Inst_MaskOffLower16Bits(cAvidaContext & ctx)7783 bool cHardwareCPU::Inst_MaskOffLower16Bits(cAvidaContext& ctx)
7784 {
7785   const int reg = FindModifiedRegister(REG_BX);
7786   GetRegister(reg) = GetRegister(reg) & MASKOFF_LOWEST16;
7787   return true;
7788 }
7789 
7790 // masks lower 16 bits in ?AX? register
Inst_MaskOffLower16Bits_defaultAX(cAvidaContext & ctx)7791 bool cHardwareCPU::Inst_MaskOffLower16Bits_defaultAX(cAvidaContext& ctx)
7792 {
7793   const int reg = FindModifiedRegister(REG_AX);
7794   GetRegister(reg) = GetRegister(reg) & MASKOFF_LOWEST16;
7795   return true;
7796 }
7797 
7798 // masks lower 15 bits in ?BX? register
Inst_MaskOffLower15Bits(cAvidaContext & ctx)7799 bool cHardwareCPU::Inst_MaskOffLower15Bits(cAvidaContext& ctx)
7800 {
7801   const int reg = FindModifiedRegister(REG_BX);
7802   GetRegister(reg) = GetRegister(reg) & MASKOFF_LOWEST15;
7803   return true;
7804 }
7805 
7806 // masks lower 15 bits in ?AX? register
Inst_MaskOffLower15Bits_defaultAX(cAvidaContext & ctx)7807 bool cHardwareCPU::Inst_MaskOffLower15Bits_defaultAX(cAvidaContext& ctx)
7808 {
7809   const int reg = FindModifiedRegister(REG_AX);
7810   GetRegister(reg) = GetRegister(reg) & MASKOFF_LOWEST15;
7811   return true;
7812 }
7813 
7814 // masks lower 14 bits in ?BX? register
Inst_MaskOffLower14Bits(cAvidaContext & ctx)7815 bool cHardwareCPU::Inst_MaskOffLower14Bits(cAvidaContext& ctx)
7816 {
7817   const int reg = FindModifiedRegister(REG_BX);
7818   GetRegister(reg) = GetRegister(reg) & MASKOFF_LOWEST14;
7819   return true;
7820 }
7821 
7822 // masks lower 14 bits in ?AX? register
Inst_MaskOffLower14Bits_defaultAX(cAvidaContext & ctx)7823 bool cHardwareCPU::Inst_MaskOffLower14Bits_defaultAX(cAvidaContext& ctx)
7824 {
7825   const int reg = FindModifiedRegister(REG_AX);
7826   GetRegister(reg) = GetRegister(reg) & MASKOFF_LOWEST14;
7827   return true;
7828 }
7829 
7830 // masks lower 13 bits in ?BX? register
Inst_MaskOffLower13Bits(cAvidaContext & ctx)7831 bool cHardwareCPU::Inst_MaskOffLower13Bits(cAvidaContext& ctx)
7832 {
7833   const int reg = FindModifiedRegister(REG_BX);
7834   GetRegister(reg) = GetRegister(reg) & MASKOFF_LOWEST13;
7835   return true;
7836 }
7837 
7838 // masks lower 13 bits in ?AX? register
Inst_MaskOffLower13Bits_defaultAX(cAvidaContext & ctx)7839 bool cHardwareCPU::Inst_MaskOffLower13Bits_defaultAX(cAvidaContext& ctx)
7840 {
7841   const int reg = FindModifiedRegister(REG_AX);
7842   GetRegister(reg) = GetRegister(reg) & MASKOFF_LOWEST13;
7843   return true;
7844 }
7845 
7846 // masks lower 12 bits in ?BX? register
Inst_MaskOffLower12Bits(cAvidaContext & ctx)7847 bool cHardwareCPU::Inst_MaskOffLower12Bits(cAvidaContext& ctx)
7848 {
7849   const int reg = FindModifiedRegister(REG_BX);
7850   GetRegister(reg) = GetRegister(reg) & MASKOFF_LOWEST12;
7851   return true;
7852 }
7853 
7854 // masks lower 12 bits in ?AX? register
Inst_MaskOffLower12Bits_defaultAX(cAvidaContext & ctx)7855 bool cHardwareCPU::Inst_MaskOffLower12Bits_defaultAX(cAvidaContext& ctx)
7856 {
7857   const int reg = FindModifiedRegister(REG_AX);
7858   GetRegister(reg) = GetRegister(reg) & MASKOFF_LOWEST12;
7859   return true;
7860 }
7861 
7862 // masks lower 8 bits in ?BX? register
Inst_MaskOffLower8Bits(cAvidaContext & ctx)7863 bool cHardwareCPU::Inst_MaskOffLower8Bits(cAvidaContext& ctx)
7864 {
7865   const int reg = FindModifiedRegister(REG_BX);
7866   GetRegister(reg) = GetRegister(reg) & MASKOFF_LOWEST8;
7867   return true;
7868 }
7869 
7870 // masks lower 8 bits in ?AX? register
Inst_MaskOffLower8Bits_defaultAX(cAvidaContext & ctx)7871 bool cHardwareCPU::Inst_MaskOffLower8Bits_defaultAX(cAvidaContext& ctx)
7872 {
7873   const int reg = FindModifiedRegister(REG_AX);
7874   GetRegister(reg) = GetRegister(reg) & MASKOFF_LOWEST8;
7875   return true;
7876 }
7877 
7878 // masks lower 4 bits in ?BX? register
Inst_MaskOffLower4Bits(cAvidaContext & ctx)7879 bool cHardwareCPU::Inst_MaskOffLower4Bits(cAvidaContext& ctx)
7880 {
7881   const int reg = FindModifiedRegister(REG_BX);
7882   GetRegister(reg) = GetRegister(reg) & MASKOFF_LOWEST4;
7883   return true;
7884 }
7885 
7886 // masks lower 4 bits in ?AX? register
Inst_MaskOffLower4Bits_defaultAX(cAvidaContext & ctx)7887 bool cHardwareCPU::Inst_MaskOffLower4Bits_defaultAX(cAvidaContext& ctx)
7888 {
7889   const int reg = FindModifiedRegister(REG_AX);
7890   GetRegister(reg) = GetRegister(reg) & MASKOFF_LOWEST4;
7891   return true;
7892 }
7893 
7894 /*! Send a message to the organism that is currently faced by this cell,
7895  where the label field of sent message is from register ?BX?, and the data field
7896  is from register ~?BX?.
7897  */
Inst_SendMessage(cAvidaContext & ctx)7898 bool cHardwareCPU::Inst_SendMessage(cAvidaContext& ctx)
7899 {
7900   return SendMessage(ctx);
7901 }
7902 
7903 // Same as cHardwareCPU::Inst_SendMessage.  Added for clearity
Inst_SendMessageInterruptType0(cAvidaContext & ctx)7904 bool cHardwareCPU::Inst_SendMessageInterruptType0(cAvidaContext& ctx) { return SendMessage(ctx, 0); }
Inst_SendMessageInterruptType1(cAvidaContext & ctx)7905 bool cHardwareCPU::Inst_SendMessageInterruptType1(cAvidaContext& ctx) { return SendMessage(ctx, 1); }
Inst_SendMessageInterruptType2(cAvidaContext & ctx)7906 bool cHardwareCPU::Inst_SendMessageInterruptType2(cAvidaContext& ctx) { return SendMessage(ctx, 2); }
Inst_SendMessageInterruptType3(cAvidaContext & ctx)7907 bool cHardwareCPU::Inst_SendMessageInterruptType3(cAvidaContext& ctx) { return SendMessage(ctx, 3); }
Inst_SendMessageInterruptType4(cAvidaContext & ctx)7908 bool cHardwareCPU::Inst_SendMessageInterruptType4(cAvidaContext& ctx) { return SendMessage(ctx, 4); }
Inst_SendMessageInterruptType5(cAvidaContext & ctx)7909 bool cHardwareCPU::Inst_SendMessageInterruptType5(cAvidaContext& ctx) { return SendMessage(ctx, 5); }
7910 
7911 // jumps one instruction passed end-handler
Inst_START_Handler(cAvidaContext & ctx)7912 bool cHardwareCPU::Inst_START_Handler(cAvidaContext& ctx)
7913 {
7914   m_advance_ip = false;
7915   //Jump 1 instruction passed msg-handler
7916   cInstruction label_inst = GetInstSet().GetInst("end-handler");
7917 
7918   cHeadCPU search_head(IP());
7919   int start_pos = search_head.GetPosition();
7920   search_head++;
7921 
7922   while (start_pos != search_head.GetPosition()) {
7923     if (search_head.GetInst() == label_inst) {
7924       // move IP to here
7925       search_head++;
7926       IP().Set(search_head.GetPosition());
7927       return true;
7928     }
7929     search_head++;
7930   }
7931 
7932   return false;
7933 }
7934 
Inst_End_Handler(cAvidaContext & ctx)7935 bool cHardwareCPU::Inst_End_Handler(cAvidaContext& ctx)
7936 {
7937   //should a thread be killed?
7938   if (m_threads[m_cur_thread].getMessageTriggerType() == -1) {
7939     return true; // thread not triggered by active message
7940   }
7941 
7942   if (!KillThread()) { // return false if one thread exists.
7943     m_organism->Fault(FAULT_LOC_THREAD_KILL, FAULT_TYPE_KILL_TH);
7944     // might need to set inst. advance to false.
7945   } // previous thread is now restored
7946 
7947   return true;
7948 }
7949 
7950 
SendMessage(cAvidaContext & ctx,int messageType)7951 bool cHardwareCPU::SendMessage(cAvidaContext& ctx, int messageType)
7952 {
7953   const int label_reg = FindModifiedRegister(REG_BX);
7954   const int data_reg = FindNextRegister(label_reg);
7955 
7956   cOrgMessage msg = cOrgMessage(m_organism, messageType);
7957   msg.SetLabel(GetRegister(label_reg));
7958   msg.SetData(GetRegister(data_reg));
7959 
7960   return m_organism->SendMessage(ctx, msg);
7961 }
7962 
7963 /*! This method /attempts/ to retrieve a message -- It may not be possible, as in
7964  the case of an empty receive buffer.
7965 
7966  If a message is available, ?BX? is set to the message's label, and ~?BX? is set
7967  to its data.
7968  */
Inst_RetrieveMessage(cAvidaContext & ctx)7969 bool cHardwareCPU::Inst_RetrieveMessage(cAvidaContext& ctx)
7970 {
7971   std::pair<bool, cOrgMessage> retrieved = m_organism->RetrieveMessage();
7972   if (!retrieved.first) {
7973     return false;
7974   }
7975 
7976   const int label_reg = FindModifiedRegister(REG_BX);
7977   const int data_reg = FindNextRegister(label_reg);
7978 
7979   GetRegister(label_reg) = retrieved.second.GetLabel();
7980   GetRegister(data_reg) = retrieved.second.GetData();
7981   return true;
7982 }
7983 
Inst_Alarm_MSG_multihop(cAvidaContext & ctx)7984 bool cHardwareCPU::Inst_Alarm_MSG_multihop(cAvidaContext& ctx)
7985 {
7986   const int reg_used = FindModifiedRegister(REG_BX);
7987   return m_organism->BcastAlarmMSG(ctx, abs(GetRegister(reg_used)%2), m_world->GetConfig().BCAST_HOPS.Get()); // jump to Alarm-label-  odd=high  even=low
7988 }
7989 
Inst_Alarm_MSG_Bit_Cons24_multihop(cAvidaContext & ctx)7990 bool cHardwareCPU::Inst_Alarm_MSG_Bit_Cons24_multihop(cAvidaContext& ctx)
7991 {
7992   const int reg_used = FindModifiedRegister(REG_BX);
7993   return m_organism->BcastAlarmMSG(ctx, (BitCount(GetRegister(reg_used) & MASK24) >= CONSENSUS24) ? 1 : 0, m_world->GetConfig().BCAST_HOPS.Get());// jump to Alarm-label-high OR Alarm-label-low
7994 }
7995 
Inst_Alarm_MSG_local(cAvidaContext & ctx)7996 bool cHardwareCPU::Inst_Alarm_MSG_local(cAvidaContext& ctx)
7997 {
7998   const int reg_used = FindModifiedRegister(REG_BX);
7999   return m_organism->BcastAlarmMSG(ctx, abs(GetRegister(reg_used)%2), 1); // jump to Alarm-label-  odd=high  even=low
8000 }
8001 
Inst_Alarm_MSG_Bit_Cons24_local(cAvidaContext & ctx)8002 bool cHardwareCPU::Inst_Alarm_MSG_Bit_Cons24_local(cAvidaContext& ctx)
8003 {
8004   const int reg_used = FindModifiedRegister(REG_BX);
8005   return m_organism->BcastAlarmMSG(ctx, (BitCount(GetRegister(reg_used) & MASK24) >= CONSENSUS24) ? 1 : 0, 1);// jump to Alarm-label-high OR Alarm-label-low
8006 }
8007 
8008 
Inst_Alarm_Label(cAvidaContext & ctx)8009 bool cHardwareCPU::Inst_Alarm_Label(cAvidaContext& ctx)
8010 {
8011   return true;
8012 }
8013 
Jump_To_Alarm_Label(int jump_label)8014 bool cHardwareCPU::Jump_To_Alarm_Label(int jump_label)
8015 {
8016   if (m_organism->IsSleeping()) {
8017     return false;
8018   }
8019 
8020   cString channel;
8021 
8022   if (jump_label == 1) {
8023     channel = "high";
8024   } else if (jump_label == 0) {
8025     channel = "low";
8026   } else {
8027     assert(false);
8028   }
8029 
8030   cInstruction label_inst = GetInstSet().GetInst(cStringUtil::Stringf("alarm-label-")+channel);
8031 
8032   cHeadCPU search_head(getIP());
8033   int start_pos = search_head.GetPosition();
8034   search_head++;
8035 
8036   while (start_pos != search_head.GetPosition()) {
8037     if (search_head.GetInst() == label_inst) {
8038       // move IP to here
8039       getIP().Set(search_head.GetPosition());
8040       m_advance_ip = false; // Don't automatically move the IP
8041       return true;
8042     }
8043     search_head++;
8044   }
8045 
8046   return false;
8047 }
8048 
8049 
8050 //// Placebo insts ////
Inst_Skip(cAvidaContext & ctx)8051 bool cHardwareCPU::Inst_Skip(cAvidaContext& ctx)
8052 {
8053   getIP().Advance();
8054   return true;
8055 }
8056 
8057 // @BDC Pheromone-related instructions
Inst_PheroOn(cAvidaContext & ctx)8058 bool cHardwareCPU::Inst_PheroOn(cAvidaContext& ctx)
8059 {
8060   m_organism->SetPheromone(true);
8061   return true;
8062 } //End Inst_PheroOn()
8063 
Inst_PheroOff(cAvidaContext & ctx)8064 bool cHardwareCPU::Inst_PheroOff(cAvidaContext& ctx)
8065 {
8066   m_organism->SetPheromone(false);
8067   return true;
8068 } //End Inst_PheroOff()
8069 
Inst_PheroToggle(cAvidaContext & ctx)8070 bool cHardwareCPU::Inst_PheroToggle(cAvidaContext& ctx)
8071 {
8072   m_organism->TogglePheromone();
8073   return true;
8074 } //End Inst_PheroToggle()
8075 
8076 // BDC: same as DoSense, but uses senses from cell that org is facing
DoSenseFacing(cAvidaContext & ctx,int conversion_method,double base)8077 bool cHardwareCPU::DoSenseFacing(cAvidaContext& ctx, int conversion_method, double base)
8078 {
8079   cPopulationCell& mycell = m_world->GetPopulation().GetCell(m_organism->GetCellID());
8080 
8081   int faced_id = mycell.GetCellFaced().GetID();
8082 
8083   // Returns the amount of a resource or resources
8084   // specified by modifying NOPs into register BX
8085   const tArray<double> & res_count = m_world->GetPopulation().GetCellResources(faced_id, ctx);
8086 
8087   // Arbitrarily set to BX since the conditional instructions use this directly.
8088   int reg_to_set = REG_BX;
8089 
8090   // There are no resources, return
8091   if (res_count.GetSize() == 0) return false;
8092 
8093   // Only recalculate logs if these values have changed
8094   static int last_num_resources = 0;
8095   static int max_label_length = 0;
8096   int num_nops = GetInstSet().GetNumNops();
8097 
8098   if ((last_num_resources != res_count.GetSize())) {
8099     max_label_length = (int) ceil(log((double)res_count.GetSize())/log((double)num_nops));
8100     last_num_resources = res_count.GetSize();
8101   }
8102 
8103   // Convert modifying NOPs to the index of the resource.
8104   // If there are fewer than the number of NOPs required
8105   // to uniquely specify a resource, then add together
8106   // a subset of resources (motivation: regulation can evolve
8107   // to be more specific if there is an advantage)
8108 
8109   // Find the maximum number of NOPs needed to specify this number of resources
8110   // Note: It's a bit wasteful to recalculate this every time and organisms will
8111   // definitely be confused if the number of resources changes during a run
8112   // because their mapping to resources will be disrupted
8113 
8114   // Attempt to read a label with this maximum length
8115   ReadLabel(max_label_length);
8116 
8117   // Find the length of the label that we actually obtained (max is max_reg_needed)
8118   int real_label_length = GetLabel().GetSize();
8119 
8120   // Start and end labels to define the start and end indices of
8121   // resources that we need to add together
8122   cCodeLabel start_label = cCodeLabel(GetLabel());
8123   cCodeLabel   end_label = cCodeLabel(GetLabel());
8124 
8125   for (int i = 0; i < max_label_length - real_label_length; i++) {
8126     start_label.AddNop(0);
8127     end_label.AddNop(num_nops-1);
8128   }
8129 
8130   int start_index = start_label.AsInt(num_nops);
8131   int   end_index =   end_label.AsInt(num_nops);
8132 
8133   // If the label refers to ONLY resources that
8134   // do not exist, then the operation fails
8135   if (start_index >= res_count.GetSize()) return false;
8136 
8137   // Otherwise sum all valid resources that it might refer to
8138   // (this will only be ONE if the label was of the maximum length).
8139   int resource_result = 0;
8140   double dresource_result = 0;
8141   for (int i = start_index; i <= end_index; i++) {
8142     // if it's a valid resource
8143     if (i < res_count.GetSize()) {
8144       if (conversion_method == 0) { // Log
8145         // for log, add together and then take log
8146         dresource_result += (double) res_count[i];
8147       }
8148       else if (conversion_method == 1) { // Addition of multiplied resource amount
8149         int add_amount = (int) (res_count[i] * base);
8150         // Do some range checking to make sure we don't overflow
8151         resource_result = (INT_MAX - resource_result <= add_amount) ? INT_MAX : resource_result + add_amount;
8152       }
8153     }
8154   }
8155 
8156   // Take the log after adding resource amounts together! This way a zero can be assigned to INT_MIN
8157   if (conversion_method == 0) {  // Log2
8158     // You really shouldn't be using the log method if you can get to zero resources
8159     if (dresource_result == 0.0) {
8160       resource_result = INT_MIN;
8161     } else {
8162       resource_result = (int)(log(dresource_result)/log(base));
8163     }
8164   }
8165 
8166   //Dump this value into an arbitrary register: BX
8167   GetRegister(reg_to_set) = resource_result;
8168 
8169   //We have to convert this to a different index that includes all degenerate labels possible: shortest to longest
8170   int sensed_index = 0;
8171   int on = 1;
8172 
8173   for (int i = 0; i < real_label_length; i++) {
8174     sensed_index += on;
8175     on *= num_nops;
8176   }
8177 
8178   sensed_index+= GetLabel().AsInt(num_nops);
8179   m_organism->GetPhenotype().IncSenseCount(sensed_index);
8180 
8181   return true;
8182 
8183   // Note that we are converting <double> resources to <int> register values
8184 } //End DoSenseFacing()
8185 
Inst_SenseLog2Facing(cAvidaContext & ctx)8186 bool cHardwareCPU::Inst_SenseLog2Facing(cAvidaContext& ctx)
8187 {
8188   return DoSenseFacing(ctx, 0, 2);
8189 }
8190 
Inst_SenseUnitFacing(cAvidaContext & ctx)8191 bool cHardwareCPU::Inst_SenseUnitFacing(cAvidaContext& ctx)
8192 {
8193   return DoSenseFacing(ctx, 1, 1);
8194 }
8195 
Inst_SenseMult100Facing(cAvidaContext & ctx)8196 bool cHardwareCPU::Inst_SenseMult100Facing(cAvidaContext& ctx)
8197 {
8198   return DoSenseFacing(ctx, 1, 100);
8199 }
8200 
8201 // Sense if the organism is on a target -- put 1 in reg is so, 0 otherwise
Inst_SenseTarget(cAvidaContext & ctx)8202 bool cHardwareCPU::Inst_SenseTarget(cAvidaContext& ctx)
8203 {
8204   int reg_to_set = FindModifiedRegister(REG_CX);
8205   int cellid = m_organism->GetCellID();
8206 
8207   if (cellid == -1) {
8208     return false;
8209   }
8210 
8211   int cell_data = m_world->GetPopulation().GetCell(cellid).GetCellData();
8212   int val = 0;
8213 
8214   if (cell_data > 0) {
8215     val = 1;
8216   }
8217 
8218   GetRegister(reg_to_set) = val;
8219 
8220   return true;
8221 } //End Inst_SenseTarget()
8222 
8223 
8224 // Sense if the cell faced is a target -- put 1 in reg is so, 0 otherwise
Inst_SenseTargetFaced(cAvidaContext & ctx)8225 bool cHardwareCPU::Inst_SenseTargetFaced(cAvidaContext& ctx)
8226 {
8227   int reg_to_set = FindModifiedRegister(REG_CX);
8228 
8229   cPopulation& pop = m_world->GetPopulation();
8230   int cellid = m_organism->GetCellID();
8231 
8232   if (cellid == -1) {
8233     return false;
8234   }
8235 
8236   cPopulationCell& mycell = pop.GetCell(cellid);
8237 
8238   int cell_data = mycell.GetCellFaced().GetCellData(); //absolute id of faced cell
8239   int val = 0;
8240 
8241   if (cell_data > 0) {
8242     val = 1;
8243   }
8244 
8245   GetRegister(reg_to_set) = val;
8246 
8247   return true;
8248 } //End Inst_SenseTargetFaced()
8249 
8250 
8251 // DoSensePheromone -- modified version of DoSense to only sense from
8252 // pheromone resource in given cell
DoSensePheromone(cAvidaContext & ctx,int cellid)8253 bool cHardwareCPU::DoSensePheromone(cAvidaContext& ctx, int cellid)
8254 {
8255   int reg_to_set = FindModifiedRegister(REG_BX);
8256 
8257   if (cellid == -1) {
8258     return false;
8259   }
8260 
8261   cPopulation& pop = m_world->GetPopulation();
8262   cDeme &deme = pop.GetDeme(pop.GetCell(cellid).GetDemeID());
8263   int relative_cell_id = deme.GetRelativeCellID(cellid);
8264 
8265   const cResourceCount& deme_resource_count = deme.GetDemeResourceCount();
8266   tArray<double> cell_resources = deme_resource_count.GetCellResources(relative_cell_id, ctx);
8267   double pher_amount = 0;
8268 
8269   if (deme_resource_count.GetSize() == 0) return false;
8270 
8271   for (int i = 0; i < deme_resource_count.GetSize(); i++) {
8272     if (strncmp(deme_resource_count.GetResName(i), "pheromone", 9) == 0) {
8273       pher_amount += cell_resources[i];
8274     }
8275   }
8276 
8277   // In Visual Studio 2005 round function does not exist use floor instead
8278   //  GetRegister(reg_to_set) = (int)round(pher_amount);
8279 
8280   GetRegister(reg_to_set) = (int)floor(pher_amount + 0.5);
8281 
8282   return true;
8283 
8284 } //End DoSensePheromone()
8285 
8286 
DoSensePheromoneInDemeGlobal(cAvidaContext & ctx,tRegisters REG_DEFAULT)8287 bool cHardwareCPU::DoSensePheromoneInDemeGlobal(cAvidaContext& ctx, tRegisters REG_DEFAULT)
8288 {
8289   if (m_organism->GetCellID() == -1) {
8290     return false;
8291   }
8292   int reg_to_set = FindModifiedRegister(REG_DEFAULT);
8293   cDeme& deme = m_world->GetPopulation().GetDeme(m_organism->GetDemeID());
8294   const cResourceCount& deme_resource_count = deme.GetDemeResourceCount();
8295 
8296   if (deme_resource_count.GetSize() == 0) assert(false); // change to: return false;
8297 
8298   double pher_amount = 0;
8299   for (int i = 0; i < deme_resource_count.GetSize(); i++) {
8300     if (strncmp(deme_resource_count.GetResName(i), "pheromone", 9) == 0) {
8301       pher_amount += deme_resource_count.Get(ctx, i);
8302     }
8303   }
8304   GetRegister(reg_to_set) = (int)floor(pher_amount + 0.5);
8305 
8306   return true;
8307 }
8308 
DoSensePheromoneGlobal(cAvidaContext & ctx,tRegisters REG_DEFAULT)8309 bool cHardwareCPU::DoSensePheromoneGlobal(cAvidaContext& ctx, tRegisters REG_DEFAULT)
8310 {
8311   int reg_to_set = FindModifiedRegister(REG_DEFAULT);
8312 
8313   const cResourceLib& resLib = m_world->GetEnvironment().GetResourceLib();
8314   const tArray<double>& resource_count_array = m_organism->GetOrgInterface().GetResources(ctx);
8315   const cResourceCount& resource_count = m_world->GetPopulation().GetResourceCount();
8316 
8317   if (resource_count.GetSize() == 0) assert(false); // change to: return false;
8318 
8319   double pher_amount = 0;
8320   cResource* res = resLib.GetResource("pheromone");
8321 
8322   if (strncmp(resource_count.GetResName(res->GetID()), "pheromone", 9) == 0) {
8323     pher_amount += resource_count_array[res->GetID()];
8324   }
8325 
8326   GetRegister(reg_to_set) = static_cast<int>(floor(pher_amount + 0.5));
8327 
8328   return true;
8329 }
8330 
8331 
Inst_SensePheromone(cAvidaContext & ctx)8332 bool cHardwareCPU::Inst_SensePheromone(cAvidaContext& ctx)
8333 {
8334   int cellid = m_organism->GetCellID(); //absolute id of current cell
8335 
8336   if (cellid == -1) {
8337     return false;
8338   }
8339 
8340   return DoSensePheromone(ctx, cellid);
8341 } //End Inst_SensePheromone()
8342 
8343 
Inst_SensePheromoneFaced(cAvidaContext & ctx)8344 bool cHardwareCPU::Inst_SensePheromoneFaced(cAvidaContext& ctx)
8345 {
8346   int cellid = m_organism->GetCellID(); //absolute id of current cell
8347 
8348   if (cellid == -1) {
8349     return false;
8350   }
8351 
8352   cPopulation& pop = m_world->GetPopulation();
8353   cPopulationCell& mycell = pop.GetCell(cellid);
8354 
8355   int fcellid = mycell.GetCellFaced().GetID(); //absolute id of faced cell
8356 
8357   return DoSensePheromone(ctx, fcellid);
8358 } //End Inst_SensePheromoneFacing()
8359 
8360 
Inst_SensePheromoneInDemeGlobal(cAvidaContext & ctx)8361 bool cHardwareCPU::Inst_SensePheromoneInDemeGlobal(cAvidaContext& ctx)
8362 {
8363   return DoSensePheromoneInDemeGlobal(ctx, REG_BX);
8364 }
8365 
Inst_SensePheromoneGlobal(cAvidaContext & ctx)8366 bool cHardwareCPU::Inst_SensePheromoneGlobal(cAvidaContext& ctx)
8367 {
8368   return DoSensePheromoneGlobal(ctx, REG_BX);
8369 }
8370 
Inst_SensePheromoneGlobal_defaultAX(cAvidaContext & ctx)8371 bool cHardwareCPU::Inst_SensePheromoneGlobal_defaultAX(cAvidaContext& ctx)
8372 {
8373   return DoSensePheromoneGlobal(ctx, REG_AX);
8374 }
8375 
Inst_Exploit(cAvidaContext & ctx)8376 bool cHardwareCPU::Inst_Exploit(cAvidaContext& ctx)
8377 {
8378   int num_rotations = 0;
8379   double phero_amount = 0;
8380   double max_pheromone = 0;
8381 
8382   cPopulation& pop = m_world->GetPopulation();
8383   int cellid = m_organism->GetCellID();
8384 
8385   if (cellid == -1) return false;
8386 
8387   cPopulationCell& mycell = pop.GetCell(cellid);
8388   cDeme &deme = pop.GetDeme(pop.GetCell(cellid).GetDemeID());
8389   const cResourceCount& deme_resource_count = deme.GetDemeResourceCount();
8390   tArray<double> cell_resources;
8391 
8392   if ( (m_world->GetConfig().EXPLOIT_EXPLORE_PROB.Get() >= 0) &&
8393       (m_world->GetRandom().P(m_world->GetConfig().EXPLOIT_EXPLORE_PROB.Get())) ) {
8394     num_rotations = ctx.GetRandom().GetUInt(m_organism->GetNeighborhoodSize());
8395   } else {
8396     // Find which neighbor has the strongest pheromone
8397     for (int i = 0; i < mycell.ConnectionList().GetSize(); i++) {
8398 
8399       phero_amount = 0;
8400       cell_resources = deme_resource_count.GetCellResources(deme.GetRelativeCellID(mycell.GetCellFaced().GetID()), ctx);
8401 
8402       for (int j = 0; j < deme_resource_count.GetSize(); j++) {
8403         if (strncmp(deme_resource_count.GetResName(j), "pheromone", 9) == 0) {
8404           phero_amount += cell_resources[j];
8405         }
8406       }
8407 
8408       if (phero_amount > max_pheromone) {
8409         num_rotations = i;
8410         max_pheromone = phero_amount;
8411       }
8412 
8413       mycell.ConnectionList().CircNext();
8414     }
8415   }
8416 
8417   // Rotate until we face the neighbor with the strongest pheromone.
8418   // If there was no winner, just move forward.
8419   for (int i = 0; i < num_rotations; i++) mycell.ConnectionList().CircNext();
8420 
8421   m_organism->Move(ctx);
8422 
8423   return true;
8424 } //End Inst_Exploit()
8425 
8426 
8427 
8428 // Sense neighboring cells, and rotate and move to the neighbor with the
8429 // strongest pheromone.  If there is no winner, just move forward.
8430 // This instruction doesn't sense the three cells behind the organism,
8431 // i.e. the one directly behind, and behind and to the left and right.
Inst_ExploitForward5(cAvidaContext & ctx)8432 bool cHardwareCPU::Inst_ExploitForward5(cAvidaContext& ctx)
8433 {
8434   int num_rotations = 0;
8435   double phero_amount = 0;
8436   double max_pheromone = 0;
8437 
8438   cPopulation& pop = m_world->GetPopulation();
8439   int cellid = m_organism->GetCellID();
8440 
8441   if (cellid == -1) {
8442     return false;
8443   }
8444 
8445   cPopulationCell& mycell = pop.GetCell(cellid);
8446   cDeme &deme = pop.GetDeme(pop.GetCell(cellid).GetDemeID());
8447   const cResourceCount& deme_resource_count = deme.GetDemeResourceCount();
8448   tArray<double> cell_resources;
8449 
8450   if ( (m_world->GetConfig().EXPLOIT_EXPLORE_PROB.Get() >= 0) &&
8451      (m_world->GetRandom().P(m_world->GetConfig().EXPLOIT_EXPLORE_PROB.Get())) ) {
8452     num_rotations = ctx.GetRandom().GetUInt(m_organism->GetNeighborhoodSize());
8453   } else {
8454     // Find which neighbor has the strongest pheromone
8455     for (int i = 0; i < mycell.ConnectionList().GetSize(); i++) {
8456 
8457       // Skip the cells in the back
8458       if (i == 3 || i == 4 || i == 5) {
8459         mycell.ConnectionList().CircNext();
8460         continue;
8461       }
8462 
8463       phero_amount = 0;
8464       cell_resources = deme_resource_count.GetCellResources(deme.GetRelativeCellID(mycell.GetCellFaced().GetID()), ctx);
8465 
8466       for (int j = 0; j < deme_resource_count.GetSize(); j++) {
8467         if (strncmp(deme_resource_count.GetResName(j), "pheromone", 9) == 0) {
8468           phero_amount += cell_resources[j];
8469         }
8470       }
8471 
8472       if (phero_amount > max_pheromone) {
8473         num_rotations = i;
8474         max_pheromone = phero_amount;
8475       }
8476 
8477       mycell.ConnectionList().CircNext();
8478     }
8479   }
8480 
8481   // Rotate until we face the neighbor with the strongest pheromone.
8482   // If there was no winner, just move forward.
8483   for (int i = 0; i < num_rotations; i++) {
8484     mycell.ConnectionList().CircNext();
8485   }
8486 
8487   m_organism->Move(ctx);
8488 
8489   return true;
8490 } //End Inst_ExploitForward5()
8491 
8492 
8493 // Sense neighboring cells, and rotate and move to the neighbor with the
8494 // strongest pheromone.  If there is no winner, just move forward.
8495 // This instruction doesn't sense the three cells behind the organism,
8496 // or the ones to the sides.
Inst_ExploitForward3(cAvidaContext & ctx)8497 bool cHardwareCPU::Inst_ExploitForward3(cAvidaContext& ctx)
8498 {
8499   int num_rotations = 0;
8500   double phero_amount = 0;
8501   double max_pheromone = 0;
8502 
8503   cPopulation& pop = m_world->GetPopulation();
8504   int cellid = m_organism->GetCellID();
8505 
8506   if (cellid == -1) {
8507     return false;
8508   }
8509 
8510   cPopulationCell& mycell = pop.GetCell(cellid);
8511   cDeme &deme = pop.GetDeme(pop.GetCell(cellid).GetDemeID());
8512   const cResourceCount& deme_resource_count = deme.GetDemeResourceCount();
8513   tArray<double> cell_resources;
8514 
8515   if ( (m_world->GetConfig().EXPLOIT_EXPLORE_PROB.Get() >= 0) &&
8516      (m_world->GetRandom().P(m_world->GetConfig().EXPLOIT_EXPLORE_PROB.Get())) ) {
8517     num_rotations = ctx.GetRandom().GetUInt(m_organism->GetNeighborhoodSize());
8518   } else {
8519     // Find which neighbor has the strongest pheromone
8520     for (int i = 0; i < mycell.ConnectionList().GetSize(); i++) {
8521 
8522       // Skip the cells in the back
8523       if (i == 2 || i == 3 || i == 4 || i == 5 || i == 6) {
8524         mycell.ConnectionList().CircNext();
8525         continue;
8526       }
8527 
8528       phero_amount = 0;
8529       cell_resources = deme_resource_count.GetCellResources(deme.GetRelativeCellID(mycell.GetCellFaced().GetID()), ctx);
8530 
8531       for (int j = 0; j < deme_resource_count.GetSize(); j++) {
8532         if (strncmp(deme_resource_count.GetResName(j), "pheromone", 9) == 0) {
8533           phero_amount += cell_resources[j];
8534         }
8535       }
8536 
8537       if (phero_amount > max_pheromone) {
8538         num_rotations = i;
8539         max_pheromone = phero_amount;
8540       }
8541 
8542       mycell.ConnectionList().CircNext();
8543     }
8544   }
8545 
8546   // Rotate until we face the neighbor with the strongest pheromone.
8547   // If there was no winner, just move forward.
8548   for (int i = 0; i < num_rotations; i++) {
8549     mycell.ConnectionList().CircNext();
8550   }
8551 
8552   m_organism->Move(ctx);
8553 
8554   return true;
8555 } //End Inst_ExploitForward3()
8556 
8557 
Inst_Explore(cAvidaContext & ctx)8558 bool cHardwareCPU::Inst_Explore(cAvidaContext& ctx)
8559 {
8560   int cellid = m_organism->GetCellID();
8561 
8562   if (cellid == -1) {
8563     return true;
8564   }
8565 
8566   // Rotate randomly.  Code taken from tumble.
8567   const int num_neighbors = m_organism->GetNeighborhoodSize();
8568   for (unsigned int i = 0; i < ctx.GetRandom().GetUInt(num_neighbors); i++) {
8569     m_organism->Rotate(1);  // Rotate doesn't rotate N times, just once.
8570   }
8571 
8572   m_organism->Move(ctx);
8573 
8574   return true;
8575 } // End Inst_Explore()
8576 
8577 
8578 // This command should move the organism to the neighbor cell that is a
8579 // target.  If more than one target exists, it moves towards the last-seen
8580 // one.  If no target exists, the organism moves forward in its original
8581 // facing.
Inst_MoveTarget(cAvidaContext & ctx)8582 bool cHardwareCPU::Inst_MoveTarget(cAvidaContext& ctx)
8583 {
8584   int num_rotations = 0;
8585 
8586   cPopulation& pop = m_world->GetPopulation();
8587   int cellid = m_organism->GetCellID();
8588 
8589   if (cellid == -1) {
8590     return true;
8591   }
8592 
8593   cPopulationCell& mycell = pop.GetCell(cellid);
8594 
8595   int cell_data;
8596 
8597   cPopulationCell faced = mycell.GetCellFaced();
8598 
8599   // Find if any neighbor is a target
8600   for (int i = 0; i < mycell.ConnectionList().GetSize(); i++) {
8601     cell_data = mycell.GetCellFaced().GetCellData();
8602 
8603     if (cell_data > 0) {
8604       num_rotations = i;
8605     }
8606 
8607     mycell.ConnectionList().CircNext();
8608   }
8609 
8610   // Rotate until we face the neighbor with a target.
8611   // If there was no winner, just move forward.
8612   for (int i = 0; i < num_rotations; i++) {
8613     mycell.ConnectionList().CircNext();
8614   }
8615 
8616   m_organism->Move(ctx);
8617 
8618   return true;
8619 } // End Inst_MoveTarget()
8620 
8621 
8622 
8623 // This command should move the organism to the neighbor cell that is a
8624 // target.  If more than one target exists, it moves towards the last-seen
8625 // one.  If no target exists, the organism moves forward in its original
8626 // facing.  This version ignores the neighbors beind the organism, i.e.
8627 // the cells directly behind and behind and to the left and right.
Inst_MoveTargetForward5(cAvidaContext & ctx)8628 bool cHardwareCPU::Inst_MoveTargetForward5(cAvidaContext& ctx)
8629 {
8630   int num_rotations = 0;
8631 
8632   cPopulation& pop = m_world->GetPopulation();
8633   int cellid = m_organism->GetCellID();
8634 
8635   if (cellid == -1) {
8636     return false;
8637   }
8638 
8639   cPopulationCell& mycell = pop.GetCell(cellid);
8640 
8641   int cell_data;
8642 
8643   cPopulationCell faced = mycell.GetCellFaced();
8644 
8645   // Find if any neighbor is a target
8646   for (int i = 0; i < mycell.ConnectionList().GetSize(); i++) {
8647 
8648     // Skip the cells behind
8649     if (i == 3 || i == 4 || i == 5) {
8650       mycell.ConnectionList().CircNext();
8651       continue;
8652     }
8653 
8654     cell_data = mycell.GetCellFaced().GetCellData();
8655 
8656     if (cell_data > 0) {
8657       num_rotations = i;
8658     }
8659 
8660     mycell.ConnectionList().CircNext();
8661   }
8662 
8663   // Rotate until we face the neighbor with a target.
8664   // If there was no winner, just move forward.
8665   for (int i = 0; i < num_rotations; i++) {
8666     mycell.ConnectionList().CircNext();
8667   }
8668 
8669   m_organism->Move(ctx);
8670 
8671   return true;
8672 } // End Inst_MoveTargetForward5()
8673 
8674 
8675 // This command should move the organism to the neighbor cell that is a
8676 // target.  If more than one target exists, it moves towards the last-seen
8677 // one.  If no target exists, the organism moves forward in its original
8678 // facing.  This version ignores the neighbors beind and to the side of
8679 //  the organism
Inst_MoveTargetForward3(cAvidaContext & ctx)8680 bool cHardwareCPU::Inst_MoveTargetForward3(cAvidaContext& ctx)
8681 {
8682   int num_rotations = 0;
8683 
8684   cPopulation& pop = m_world->GetPopulation();
8685   int cellid = m_organism->GetCellID();
8686 
8687   if (cellid == -1) {
8688     return false;
8689   }
8690 
8691   cPopulationCell& mycell = pop.GetCell(cellid);
8692 
8693   int cell_data;
8694 
8695   cPopulationCell faced = mycell.GetCellFaced();
8696 
8697   // Find if any neighbor is a target
8698   for (int i = 0; i < mycell.ConnectionList().GetSize(); i++) {
8699 
8700     // Skip the cells behind
8701     if (i==2 || i == 3 || i == 4 || i == 5 || i == 6) {
8702       mycell.ConnectionList().CircNext();
8703       continue;
8704     }
8705 
8706     cell_data = mycell.GetCellFaced().GetCellData();
8707 
8708     if (cell_data > 0) {
8709       num_rotations = i;
8710     }
8711 
8712     mycell.ConnectionList().CircNext();
8713   }
8714 
8715   // Rotate until we face the neighbor with a target.
8716   // If there was no winner, just move forward.
8717   for (int i = 0; i < num_rotations; i++) {
8718     mycell.ConnectionList().CircNext();
8719   }
8720 
8721   m_organism->Move(ctx);
8722 
8723   return true;
8724 } // End Inst_MoveTargetForward3()
8725 
8726 
Inst_SuperMove(cAvidaContext & ctx)8727 bool cHardwareCPU::Inst_SuperMove(cAvidaContext& ctx)
8728 {
8729   int num_rotations = 0;
8730   float phero_amount = 0;
8731   float max_pheromone = 0;
8732 
8733   cPopulation& pop = m_world->GetPopulation();
8734   int cellid = m_organism->GetCellID();
8735 
8736   if (cellid == -1) {
8737     return false;
8738   }
8739 
8740   cPopulationCell& mycell = pop.GetCell(cellid);
8741   cDeme &deme = pop.GetDeme(pop.GetCell(cellid).GetDemeID());
8742   const cResourceCount& deme_resource_count = deme.GetDemeResourceCount();
8743   int relative_cell_id = deme.GetRelativeCellID(cellid);
8744   tArray<double> cell_resources = deme_resource_count.GetCellResources(relative_cell_id, ctx);
8745 
8746   int cell_data;
8747 
8748   // Set num_rotations to a random number for explore -- lowest priority
8749   const int num_neighbors = m_organism->GetNeighborhoodSize();
8750   num_rotations = ctx.GetRandom().GetUInt(num_neighbors);
8751 
8752 
8753   // Find the neighbor with highest pheromone -- medium priority
8754   for (int i = 0; i < mycell.ConnectionList().GetSize(); i++) {
8755 
8756     phero_amount = 0;
8757     cell_resources = deme_resource_count.GetCellResources(deme.GetRelativeCellID(mycell.GetCellFaced().GetID()), ctx);
8758 
8759     for (int j = 0; j < deme_resource_count.GetSize(); j++) {
8760       if (strncmp(deme_resource_count.GetResName(j), "pheromone", 9) == 0) {
8761         phero_amount += cell_resources[j];
8762       }
8763     }
8764 
8765     if (phero_amount > max_pheromone) {
8766       num_rotations = i;
8767       max_pheromone = phero_amount;
8768     }
8769 
8770     mycell.ConnectionList().CircNext();
8771   }
8772 
8773   // Find if any neighbor is a target -- highest priority
8774   for (int i = 0; i < mycell.ConnectionList().GetSize(); i++) {
8775     cell_data = mycell.GetCellFaced().GetCellData();
8776 
8777     if (cell_data > 0) {
8778       num_rotations = i;
8779     }
8780 
8781     mycell.ConnectionList().CircNext();
8782   }
8783 
8784   // Rotate until we face the neighbor with a target.
8785   // If there was no winner, just move forward.
8786   for (int i = 0; i < num_rotations; i++) {
8787     mycell.ConnectionList().CircNext();
8788   }
8789 
8790   m_organism->Move(ctx);
8791 
8792   return true;
8793 } // End Inst_SuperMove()
8794 
8795 
Inst_IfTarget(cAvidaContext & ctx)8796 bool cHardwareCPU::Inst_IfTarget(cAvidaContext& ctx)
8797 {
8798   int cellid = m_organism->GetCellID(); //absolute id of current cell
8799 
8800   if (cellid == -1) {
8801     return true;
8802   }
8803 
8804   int cell_data = m_world->GetPopulation().GetCell(cellid).GetCellData();
8805 
8806   if (cell_data == -1) {
8807     getIP().Advance();
8808   }
8809 
8810   return true;
8811 } //End Inst_IfTarget()
8812 
8813 
Inst_IfNotTarget(cAvidaContext & ctx)8814 bool cHardwareCPU::Inst_IfNotTarget(cAvidaContext& ctx)
8815 {
8816   int cellid = m_organism->GetCellID(); //absolute id of current cell
8817 
8818   if (cellid == -1) {
8819     return true;
8820   }
8821 
8822   int cell_data = m_world->GetPopulation().GetCell(cellid).GetCellData();
8823 
8824   if (cell_data > 0) {
8825     getIP().Advance();
8826   }
8827 
8828   return true;
8829 } //End Inst_IfNotTarget()
8830 
8831 
Inst_IfPheromone(cAvidaContext & ctx)8832 bool cHardwareCPU::Inst_IfPheromone(cAvidaContext& ctx)
8833 {
8834   int cellid = m_organism->GetCellID(); //absolute id of current cell
8835 
8836   if (cellid == -1) {
8837     return true;
8838   }
8839 
8840   cPopulation& pop = m_world->GetPopulation();
8841   cDeme &deme = pop.GetDeme(pop.GetCell(cellid).GetDemeID());
8842   int relative_cell_id = deme.GetRelativeCellID(cellid);
8843 
8844   const cResourceCount& deme_resource_count = deme.GetDemeResourceCount();
8845   tArray<double> cell_resources = deme_resource_count.GetCellResources(relative_cell_id, ctx);
8846 
8847   if (deme_resource_count.GetSize() == 0) return false;
8848 
8849   double pher_amount = 0;
8850 
8851   for (int i = 0; i < deme_resource_count.GetSize(); i++) {
8852     if (strncmp(deme_resource_count.GetResName(i), "pheromone", 9) == 0) {
8853       pher_amount += cell_resources[i];
8854     }
8855   }
8856 
8857   if (pher_amount == 0) {
8858     getIP().Advance();
8859   }
8860 
8861   return true;
8862 
8863 } //End Inst_IfPheromone()
8864 
8865 
Inst_IfNotPheromone(cAvidaContext & ctx)8866 bool cHardwareCPU::Inst_IfNotPheromone(cAvidaContext& ctx)
8867 {
8868   int cellid = m_organism->GetCellID(); //absolute id of current cell
8869 
8870   if (cellid == -1) {
8871     return true;
8872   }
8873 
8874   cPopulation& pop = m_world->GetPopulation();
8875   cDeme &deme = pop.GetDeme(pop.GetCell(cellid).GetDemeID());
8876   int relative_cell_id = deme.GetRelativeCellID(cellid);
8877 
8878   const cResourceCount& deme_resource_count = deme.GetDemeResourceCount();
8879   tArray<double> cell_resources = deme_resource_count.GetCellResources(relative_cell_id, ctx);
8880 
8881   if (deme_resource_count.GetSize() == 0) return false;
8882 
8883   double pher_amount = 0;
8884 
8885   for (int i = 0; i < deme_resource_count.GetSize(); i++) {
8886     if (strncmp(deme_resource_count.GetResName(i), "pheromone", 9) == 0) {
8887       pher_amount += cell_resources[i];
8888     }
8889   }
8890 
8891   if (pher_amount > 0) {
8892     getIP().Advance();
8893   }
8894 
8895   return true;
8896 
8897 } //End Inst_IfNotPheromone()
8898 
8899 
Inst_DropPheromone(cAvidaContext & ctx)8900 bool cHardwareCPU::Inst_DropPheromone(cAvidaContext& ctx)
8901 {
8902   cPopulation& pop = m_world->GetPopulation();
8903   int cellid = m_organism->GetCellID();
8904 
8905   if (cellid == -1) {
8906     return true;
8907   }
8908 
8909   cDeme &deme = pop.GetDeme(pop.GetCell(cellid).GetDemeID());
8910 
8911   // If organism is dropping pheromones, mark the appropriate cell
8912   // Note: right now, we're ignoring the organism's pheromone status and always
8913   //   dropping if pheromones are enabled
8914   if (m_world->GetConfig().PHEROMONE_ENABLED.Get() == 1) {
8915 
8916     const double pher_amount = m_world->GetConfig().PHEROMONE_AMOUNT.Get();
8917     //const int drop_mode =  m_world->GetConfig().PHEROMONE_DROP_MODE.Get();
8918 
8919     // We can't use the different drop modes, because we only know the cell
8920     // that the organism is currently in.
8921     /*
8922      if (drop_mode == 0) {
8923      deme.AddPheromone(fromcellID, pher_amount/2);
8924      deme.AddPheromone(destcellID, pher_amount/2);
8925      } else if (drop_mode == 1) {
8926      deme.AddPheromone(fromcellID, pher_amount);
8927      } else if (drop_mode == 2) {
8928      deme.AddPheromone(destcellID, pher_amount);
8929      }
8930      */
8931     deme.AddPheromone(cellid, pher_amount, ctx);
8932 
8933     // Write some logging information if LOG_PHEROMONE is set.  This is done
8934     // out here so that non-pheromone moves are recorded.
8935     if ( (m_world->GetConfig().LOG_PHEROMONE.Get() == 1) &&
8936 	 (m_world->GetStats().GetUpdate() >= m_world->GetConfig().PHEROMONE_LOG_START.Get()) ) {
8937       cString tmpfilename = cStringUtil::Stringf("drop-pheromone-log.dat");
8938       cDataFile& df = m_world->GetDataFile(tmpfilename);
8939 
8940       int rel_cellid = deme.GetRelativeCellID(cellid);
8941       double pher_amount;
8942       const int drop_mode =  m_world->GetConfig().PHEROMONE_DROP_MODE.Get();
8943 
8944       // By columns: update ID, org ID, source cell (relative), destination cell (relative), amount dropped, drop mode
8945       if ( (m_world->GetConfig().PHEROMONE_ENABLED.Get() == 1) &&
8946 	   (m_organism->GetPheromoneStatus() == true) ) {
8947         pher_amount = m_world->GetConfig().PHEROMONE_AMOUNT.Get();
8948       } else {
8949         pher_amount = 0;
8950       }
8951 
8952       cString UpdateStr = cStringUtil::Stringf("%d,%d,%d,%d,%f,%d",  m_world->GetStats().GetUpdate(), m_organism->GetID(), deme.GetDemeID(), rel_cellid, pher_amount, drop_mode);
8953       df.WriteRaw(UpdateStr);
8954     }
8955 
8956   } //End laying pheromone
8957 
8958   return true;
8959 
8960 } //End Inst_DropPheromone()
8961 
8962 
8963 /*! Set this organism's current opinion to the value in ?BX?.
8964  */
Inst_SetOpinion(cAvidaContext & ctx)8965 bool cHardwareCPU::Inst_SetOpinion(cAvidaContext& ctx)
8966 {
8967   assert(m_organism != 0);
8968   m_organism->GetOrgInterface().SetOpinion(GetRegister(FindModifiedRegister(REG_BX)), m_organism);
8969   return true;
8970 }
8971 
8972 
8973 /*! Sense this organism's current opinion, placing the opinion in register ?BX?
8974  and the age of that opinion (in updates) in register !?BX?.  If the organism has no
8975  opinion, do nothing.
8976  */
Inst_GetOpinion(cAvidaContext & ctx)8977 bool cHardwareCPU::Inst_GetOpinion(cAvidaContext& ctx)
8978 {
8979   assert(m_organism != 0);
8980   if (m_organism->GetOrgInterface().HasOpinion(m_organism)) {
8981     const int opinion_reg = FindModifiedRegister(REG_BX);
8982     const int age_reg = FindNextRegister(opinion_reg);
8983 
8984     GetRegister(opinion_reg) = m_organism->GetOpinion().first;
8985     GetRegister(age_reg) = m_world->GetStats().GetUpdate() - m_organism->GetOpinion().second;
8986   }
8987   return true;
8988 }
8989 
Inst_GetOpinionOnly_ZeroIfNone(cAvidaContext & ctx)8990 bool cHardwareCPU::Inst_GetOpinionOnly_ZeroIfNone(cAvidaContext& ctx)
8991 {
8992   assert(m_organism != 0);
8993   const int opinion_reg = FindModifiedRegister(REG_BX);
8994   if (m_organism->GetOrgInterface().HasOpinion(m_organism)) {
8995     GetRegister(opinion_reg) = m_organism->GetOpinion().first;
8996   } else {
8997     GetRegister(opinion_reg) = 0;
8998   }
8999 
9000   return true;
9001 }
9002 
9003 
Inst_ClearOpinion(cAvidaContext & ctx)9004 bool cHardwareCPU::Inst_ClearOpinion(cAvidaContext& ctx)
9005 {
9006   assert(m_organism != 0);
9007   m_organism->GetOrgInterface().ClearOpinion(m_organism);
9008 
9009   return true;
9010 }
9011 
9012 /*! If the organism has an opinion then execute the next instruction, else skip.
9013  */
Inst_IfOpinionSet(cAvidaContext & ctx)9014 bool cHardwareCPU::Inst_IfOpinionSet(cAvidaContext& ctx)
9015 {
9016   assert(m_organism != 0);
9017   if (!m_organism->GetOrgInterface().HasOpinion(m_organism)) getIP().Advance();
9018 
9019   return true;
9020 }
9021 
Inst_IfOpinionNotSet(cAvidaContext & ctx)9022 bool cHardwareCPU::Inst_IfOpinionNotSet(cAvidaContext& ctx)
9023 {
9024   assert(m_organism != 0);
9025   if (m_organism->GetOrgInterface().HasOpinion(m_organism)) getIP().Advance();
9026 
9027   return true;
9028 }
9029 
9030 /* Sets the organism's opinion to the number 0 and checks for completed tasks. */
Inst_SetOpinionToZero(cAvidaContext & ctx)9031 bool cHardwareCPU::Inst_SetOpinionToZero(cAvidaContext& ctx)
9032 {
9033   assert(m_organism != 0);
9034   const int out_reg = FindModifiedRegister(REG_BX);
9035   GetRegister(out_reg) = 0;
9036   m_organism->GetOrgInterface().SetOpinion(GetRegister(FindModifiedRegister(REG_BX)), m_organism);
9037   m_organism->DoOutput(ctx, 0);
9038   return true;
9039 }
9040 
9041 /* Sets the organism's opinion to the number 1 and checks for completed tasks. */
Inst_SetOpinionToOne(cAvidaContext & ctx)9042 bool cHardwareCPU::Inst_SetOpinionToOne(cAvidaContext& ctx)
9043 {
9044   assert(m_organism != 0);
9045   const int out_reg = FindModifiedRegister(REG_BX);
9046   GetRegister(out_reg) = 1;
9047   m_organism->GetOrgInterface().SetOpinion(GetRegister(FindModifiedRegister(REG_BX)), m_organism);
9048   m_organism->DoOutput(ctx, 1);
9049   return true;
9050 }
9051 
9052 /* Sets the organism's opinion to the number 2 and checks for completed tasks. */
Inst_SetOpinionToTwo(cAvidaContext & ctx)9053 bool cHardwareCPU::Inst_SetOpinionToTwo(cAvidaContext& ctx)
9054 {
9055   assert(m_organism != 0);
9056   const int out_reg = FindModifiedRegister(REG_BX);
9057   GetRegister(out_reg) = 2;
9058   m_organism->GetOrgInterface().SetOpinion(GetRegister(FindModifiedRegister(REG_BX)), m_organism);
9059   m_organism->DoOutput(ctx, 2);
9060   return true;
9061 }
9062 
9063 
9064 
9065 
9066 /*! Collect this cell's data, and place it in ?BX?.  Set the flag indicating that
9067  this organism has collected cell data to true, and set the last collected cell data
9068  as well.
9069  */
Inst_CollectCellData(cAvidaContext & ctx)9070 bool cHardwareCPU::Inst_CollectCellData(cAvidaContext& ctx)
9071 {
9072   assert(m_organism != 0);
9073   const int out_reg = FindModifiedRegister(REG_BX);
9074   GetRegister(out_reg) = m_organism->GetCellData();
9075   // Update last collected cell data:
9076   m_last_cell_data = std::make_pair(true, GetRegister(out_reg));
9077 
9078   return true;
9079 }
9080 
9081 
9082 /*! Detect if the cell data in which this organism lives has changed since the
9083  last time that this organism has collected cell data.  Note that this process
9084  DOES NOT take into account organism movement, and it only works with explicit
9085  collection of cell data.
9086  */
Inst_IfCellDataChanged(cAvidaContext & ctx)9087 bool cHardwareCPU::Inst_IfCellDataChanged(cAvidaContext& ctx)
9088 {
9089   assert(m_organism != 0);
9090   // If we haven't collected cell data yet, or it's the same as the current cell data, advance
9091   // the IP:
9092   if (!m_last_cell_data.first || (m_last_cell_data.second == m_organism->GetCellData())) {
9093     getIP().Advance();
9094   }
9095 
9096   return true;
9097 }
9098 
9099 
Inst_KillCellEvent(cAvidaContext & ctx)9100 bool cHardwareCPU::Inst_KillCellEvent(cAvidaContext& ctx)
9101 {
9102   // Fail if we're running in the test CPU.
9103   if ((m_organism->GetOrgInterface().GetDemeID() < 0) || (m_organism->GetCellID() < 0)) {
9104     return false;
9105   }
9106 
9107   const int reg = FindModifiedRegister(REG_BX);
9108   int eventID = m_organism->GetCellData();
9109   GetRegister(reg) = m_organism->GetOrgInterface().GetDeme()->KillCellEvent(eventID);
9110 
9111   return true;
9112 }
9113 
9114 
Inst_KillFacedCellEvent(cAvidaContext & ctx)9115 bool cHardwareCPU::Inst_KillFacedCellEvent(cAvidaContext& ctx)
9116 {
9117   // Fail if we're running in the test CPU.
9118   if ((m_organism->GetOrgInterface().GetDemeID() < 0) || (m_organism->GetCellID() < 0)) {
9119     return false;
9120   }
9121 
9122   const int reg = FindModifiedRegister(REG_BX);
9123   int eventID = m_organism->GetNeighborCellContents();
9124   GetRegister(reg) = m_organism->GetOrgInterface().GetDeme()->KillCellEvent(eventID);
9125 
9126   if (GetRegister(reg)) {
9127     m_organism->SetEventKilled();
9128   }
9129 
9130   return true;
9131 }
9132 
9133 
Inst_CollectCellDataAndKillEvent(cAvidaContext & ctx)9134 bool cHardwareCPU::Inst_CollectCellDataAndKillEvent(cAvidaContext& ctx)
9135 {
9136   // Fail if we're running in the test CPU.
9137   if ((m_organism->GetOrgInterface().GetDemeID() < 0) || (m_organism->GetCellID() < 0)) {
9138     return false;
9139   }
9140 
9141   const int out_reg = FindModifiedRegister(REG_BX);
9142   int eventID = m_organism->GetCellData();
9143   GetRegister(out_reg) = eventID;
9144 
9145   m_organism->GetOrgInterface().GetDeme()->KillCellEvent(eventID);
9146 
9147   return true;
9148 }
9149 
9150 
Inst_ReadCellData(cAvidaContext & ctx)9151 bool cHardwareCPU::Inst_ReadCellData(cAvidaContext& ctx)
9152 {
9153   assert(m_organism != 0);
9154   const int out_reg = FindModifiedRegister(REG_BX);
9155   GetRegister(out_reg) = m_organism->GetCellData();
9156 
9157   return true;
9158 }
9159 
Inst_ReadFacedCellData(cAvidaContext & ctx)9160 bool cHardwareCPU::Inst_ReadFacedCellData(cAvidaContext& ctx)
9161 {
9162   assert(m_organism != 0);
9163   const int out_reg = FindModifiedRegister(REG_BX);
9164   // return % diff (FacedCellData is already int)
9165   int my_vit = (int) (m_organism->GetVitality() + 0.5);
9166   int vit_diff = (m_organism->GetFacedCellData() - my_vit)/my_vit * 100;
9167   GetRegister(out_reg) = vit_diff;
9168 
9169   return true;
9170 }
9171 
Inst_ReadFacedCellDataOrgID(cAvidaContext & ctx)9172 bool cHardwareCPU::Inst_ReadFacedCellDataOrgID(cAvidaContext& ctx)
9173 {
9174   assert(m_organism != 0);
9175   const int out_reg = FindModifiedRegister(REG_BX);
9176   GetRegister(out_reg) = m_organism->GetFacedCellDataOrgID();
9177 
9178   return true;
9179 }
9180 
Inst_ReadFacedCellDataFreshness(cAvidaContext & ctx)9181 bool cHardwareCPU::Inst_ReadFacedCellDataFreshness(cAvidaContext& ctx)
9182 {
9183   assert(m_organism != 0);
9184   const int out_reg = FindModifiedRegister(REG_BX);
9185   GetRegister(out_reg) = m_world->GetStats().GetUpdate() - m_organism->GetFacedCellDataUpdate();
9186 
9187   return true;
9188 }
9189 
Inst_MarkCellWithID(cAvidaContext & ctx)9190 bool cHardwareCPU::Inst_MarkCellWithID(cAvidaContext& ctx)
9191 {
9192   assert(m_organism != 0);
9193   m_organism->SetCellData(m_organism->GetID());
9194 
9195   return true;
9196 }
9197 
Inst_GetResStored(cAvidaContext & ctx)9198 bool cHardwareCPU::Inst_GetResStored(cAvidaContext& ctx)
9199 //Get amount of stored collect specific resource (how much do I have available for res_cost instructions).
9200 {
9201   assert(m_organism != 0);
9202   const int out_reg = FindModifiedRegister(REG_BX);
9203   const int resource = m_world->GetConfig().COLLECT_SPECIFIC_RESOURCE.Get();
9204   // needs to return int...we round down so that they don't think there is more available than they need
9205   int res_stored = (int) (m_organism->GetRBin(resource) * 100 - 0.5);
9206   GetRegister(out_reg) = res_stored;
9207   return true;
9208 }
9209 
Inst_MarkCellWithVitality(cAvidaContext & ctx)9210 bool cHardwareCPU::Inst_MarkCellWithVitality(cAvidaContext& ctx)
9211 {
9212   assert(m_organism != 0);
9213   // SetCellData() needs to be int
9214   int my_vit = (int) (m_organism->GetVitality() + 0.5);
9215   m_organism->SetCellData(my_vit);
9216 
9217   return true;
9218 }
9219 
Inst_GetID(cAvidaContext & ctx)9220 bool cHardwareCPU::Inst_GetID(cAvidaContext& ctx)
9221 {
9222   assert(m_organism != 0);
9223   const int out_reg = FindModifiedRegister(REG_BX);
9224   GetRegister(out_reg) = m_organism->GetID();
9225 
9226   return true;
9227 }
9228 
Inst_GetFacedVitalityDiff(cAvidaContext & ctx)9229 bool cHardwareCPU::Inst_GetFacedVitalityDiff(cAvidaContext& ctx)
9230 //Get difference in vitality of this organism and faced neighbor.
9231 {
9232   assert(m_organism != 0);
9233 
9234   if (!m_organism->IsNeighborCellOccupied()) return false;
9235 
9236   cOrganism * neighbor = m_organism->GetNeighbor();
9237   if (neighbor->IsDead())  return false;
9238 
9239   const int out_reg = FindModifiedRegister(REG_BX);
9240   // return % diff
9241   int vit_diff = (int) ((neighbor->GetVitality() -  m_organism->GetVitality())/m_organism->GetVitality() * 100 + 0.5);
9242   GetRegister(out_reg) = vit_diff;
9243   return true;
9244 }
9245 
9246 
Inst_GetFacedOrgID(cAvidaContext & ctx)9247 bool cHardwareCPU::Inst_GetFacedOrgID(cAvidaContext& ctx)
9248 //Get ID of organism faced by this one, if there is an organism in front.
9249 {
9250   if (!m_organism->IsNeighborCellOccupied()) return false;
9251 
9252   cOrganism * neighbor = m_organism->GetNeighbor();
9253   if (neighbor->IsDead())  return false;
9254 
9255   const int out_reg = FindModifiedRegister(REG_BX);
9256   GetRegister(out_reg) = neighbor->GetID();
9257   return true;
9258 }
9259 
9260 
9261 //Attack organism faced by this one, if there is an organism in front. This will use vitality bins if those are set.
Inst_AttackFacedOrg(cAvidaContext & ctx)9262 bool cHardwareCPU::Inst_AttackFacedOrg(cAvidaContext& ctx)
9263 {
9264   assert(m_organism != 0);
9265   if (!m_organism->IsNeighborCellOccupied()) return false;
9266 
9267   cOrganism* target = m_organism->GetNeighbor();
9268   if (target->IsDead()) return false;
9269 
9270   const int target_cell = target->GetCellID();
9271 
9272   //Use vitality settings to decide who wins this battle.
9273   bool kill_attacker = true;
9274   if (m_world->GetConfig().MOVEMENT_COLLISIONS_SELECTION_TYPE.Get() == 0)
9275     // 50% chance, no modifiers
9276     kill_attacker = ctx.GetRandom().P(0.5);
9277   else if (m_world->GetConfig().MOVEMENT_COLLISIONS_SELECTION_TYPE.Get() == 1) {
9278     //vitality based
9279     const double attacker_vitality = m_organism->GetVitality();
9280     const double target_vitality = target->GetVitality();
9281     const double attacker_win_odds = ((attacker_vitality) / (attacker_vitality + target_vitality));
9282     const double target_win_odds = ((target_vitality) / (attacker_vitality + target_vitality));
9283 
9284     const double odds_someone_dies = max(attacker_win_odds, target_win_odds);
9285     const double odds_target_dies = (1 - target_win_odds) * odds_someone_dies;
9286     const double decider = ctx.GetRandom().GetDouble(1);
9287 
9288     if (decider < (1 - odds_someone_dies)) return true;
9289     else if (decider < ((1 - odds_someone_dies) + odds_target_dies)) kill_attacker = false;
9290   }
9291   if (kill_attacker) {
9292     m_organism->Die(ctx);
9293     return true;
9294   }
9295 
9296   m_world->GetPopulation().AttackFacedOrg(ctx, target_cell);
9297   return true;
9298 }
9299 
9300 //Get odds of winning or tieing in a fight. This will use vitality bins if those are set.
Inst_GetAttackOdds(cAvidaContext & ctx)9301 bool cHardwareCPU::Inst_GetAttackOdds(cAvidaContext& ctx)
9302 {
9303   assert(m_organism != 0);
9304   if (!m_organism->IsNeighborCellOccupied()) return false;
9305 
9306   cOrganism* target = m_organism->GetNeighbor();
9307   if (target->IsDead()) return false;
9308 
9309   const double attacker_vitality = m_organism->GetVitality();
9310   const double target_vitality = target->GetVitality();
9311 
9312   const double attacker_win_odds = ((attacker_vitality) / (attacker_vitality + target_vitality));
9313   const double target_win_odds = ((target_vitality) / (attacker_vitality + target_vitality));
9314 
9315   const double odds_someone_dies = max(attacker_win_odds, target_win_odds);
9316   // my win odds are odds nobody dies or someone dies and it's the target
9317   const double odds_I_dont_die = (1 - odds_someone_dies) + ((1 - target_win_odds) * odds_someone_dies);
9318 
9319   // return odds as %
9320   const int out_reg = FindModifiedRegister(REG_BX);
9321   GetRegister(out_reg) = (int) (odds_I_dont_die * 100 + 0.5);
9322   return true;
9323 }
9324 
9325 /*! Called when the organism that owns this CPU has received a flash from a neighbor. */
ReceiveFlash()9326 void cHardwareCPU::ReceiveFlash()
9327 {
9328   m_flash_info.first = 1; // Yes, we've received a flash.
9329   m_flash_info.second = m_cycle_counter; // When we received it.
9330 }
9331 
9332 
9333 /*! Send a "flash" event to all neighboring organisms. */
Inst_Flash(cAvidaContext & ctx)9334 bool cHardwareCPU::Inst_Flash(cAvidaContext& ctx)
9335 {
9336   assert(m_organism != 0);
9337   m_organism->SendFlash(ctx);
9338   return true;
9339 }
9340 
9341 
9342 /*! Test if this organism has ever recieved a flash event. */
Inst_IfRecvdFlash(cAvidaContext & ctx)9343 bool cHardwareCPU::Inst_IfRecvdFlash(cAvidaContext& ctx)
9344 {
9345   assert(m_organism != 0);
9346   if (m_flash_info.first == 0) {
9347     getIP().Advance();
9348   }
9349 
9350   return true;
9351 }
9352 
9353 
9354 /*! Retrieve if & when this organism has last received a flash. */
Inst_FlashInfo(cAvidaContext & ctx)9355 bool cHardwareCPU::Inst_FlashInfo(cAvidaContext& ctx)
9356 {
9357   assert(m_organism != 0);
9358   const int bx = FindModifiedRegister(REG_BX);
9359   const int cx = FindNextRegister(bx);
9360 
9361   if (m_flash_info.first > 0) {
9362     assert(m_cycle_counter >= m_flash_info.second);
9363     GetRegister(bx) = m_flash_info.first;
9364     GetRegister(cx) = m_cycle_counter - m_flash_info.second;
9365   } else {
9366     GetRegister(bx) = 0;
9367     GetRegister(cx) = 0;
9368   }
9369   return true;
9370 }
9371 
9372 
9373 /*! Retrieve if (but not when) this organism has last received a flash. */
Inst_FlashInfoB(cAvidaContext & ctx)9374 bool cHardwareCPU::Inst_FlashInfoB(cAvidaContext& ctx)
9375 {
9376   assert(m_organism != 0);
9377   const int bx = FindModifiedRegister(REG_BX);
9378 
9379   if (m_flash_info.first > 0) {
9380     assert(m_cycle_counter >= m_flash_info.second);
9381     GetRegister(bx) = m_flash_info.first;
9382   } else {
9383     GetRegister(bx) = 0;
9384   }
9385 
9386   return true;
9387 }
9388 
9389 
Inst_ResetFlashInfo(cAvidaContext & ctx)9390 bool cHardwareCPU::Inst_ResetFlashInfo(cAvidaContext& ctx)
9391 {
9392   assert(m_organism != 0);
9393   m_flash_info.first = 0;
9394   m_flash_info.second = 0;
9395 
9396   return true;
9397 }
9398 
9399 
Inst_HardReset(cAvidaContext & ctx)9400 bool cHardwareCPU::Inst_HardReset(cAvidaContext& ctx)
9401 {
9402   Reset(ctx);
9403   m_advance_ip = false;
9404 
9405   return true;
9406 }
9407 
9408 
9409 //! Current "time": the number of cycles this CPU has been "alive."
Inst_GetCycles(cAvidaContext & ctx)9410 bool cHardwareCPU::Inst_GetCycles(cAvidaContext& ctx)
9411 {
9412   GetRegister(FindModifiedRegister(REG_BX)) = m_cycle_counter;
9413   return true;
9414 }
9415 
9416 
9417 //! Loads the current neighborhood into the organism's memory.
Inst_GetNeighborhood(cAvidaContext & ctx)9418 bool cHardwareCPU::Inst_GetNeighborhood(cAvidaContext& ctx)
9419 {
9420   assert(m_organism != 0);
9421   m_organism->LoadNeighborhood();
9422 
9423   return true;
9424 }
9425 
9426 
9427 //! Test if the current neighborhood has changed from that in the organism's memory.
Inst_IfNeighborhoodChanged(cAvidaContext & ctx)9428 bool cHardwareCPU::Inst_IfNeighborhoodChanged(cAvidaContext& ctx)
9429 {
9430   assert(m_organism != 0);
9431   if (!m_organism->HasNeighborhoodChanged()) {
9432     getIP().Advance();
9433   }
9434 
9435   return true;
9436 }
9437 
9438 
9439 /*! Find the first occurence of the passed-in instruction from the getIP() forward,
9440  wrapping around the genome as required.  If the given instruction is not in the
9441  genome, return the starting position.
9442  */
Find(const char * instr)9443 cHeadCPU cHardwareCPU::Find(const char* instr)
9444 {
9445   cHeadCPU ptr(getIP());
9446   const int current = ptr.GetPosition();
9447   ptr.Advance();
9448   while (ptr.GetPosition() != current) {
9449     ptr.Advance();
9450     if (m_inst_set->GetName(ptr.GetInst())==instr) {
9451       break;
9452     }
9453   }
9454 
9455   return ptr;
9456 }
9457 
9458 
Inst_IfLessEnd(cAvidaContext & ctx)9459 bool cHardwareCPU::Inst_IfLessEnd(cAvidaContext& ctx)
9460 {
9461   const int x = FindModifiedRegister(REG_BX);
9462   const int y = FindNextRegister(x);
9463 
9464   if (GetRegister(x) >= GetRegister(y)) { Else_TopHalf(); }
9465   return true;
9466 }
9467 
9468 
Inst_IfNotEqualEnd(cAvidaContext & ctx)9469 bool cHardwareCPU::Inst_IfNotEqualEnd(cAvidaContext& ctx)
9470 {
9471   const int x = FindModifiedRegister(REG_BX);
9472   const int y = FindNextRegister(x);
9473 
9474   if (GetRegister(x) == GetRegister(y)) { Else_TopHalf(); }
9475   return true;
9476 }
9477 
9478 
Inst_IfGrtEquEnd(cAvidaContext & ctx)9479 bool cHardwareCPU::Inst_IfGrtEquEnd(cAvidaContext& ctx)
9480 {
9481   const int x = FindModifiedRegister(REG_BX);
9482   const int y = FindNextRegister(x);
9483 
9484   if (GetRegister(x) < GetRegister(y)) { Else_TopHalf(); }
9485   return true;
9486 }
9487 
9488 
9489 /*! This is the top-half of the else instruction, meant to be executed if the if
9490  condition evaluates to false.
9491  */
Else_TopHalf()9492 void cHardwareCPU::Else_TopHalf()
9493 {
9494   cHeadCPU else_head = Find("else");
9495   cHeadCPU endif_head = Find("endif");
9496 
9497   // Condition failed.  If there's an else-clause, jump to it.
9498   // If there isn't an else-clause, try to jump to the endif.
9499   // Note that the IP is unconditionally advanced *after* this instruction
9500   // has executed.  If there is no else or endif, advance one instruction.
9501   if (else_head.GetPosition() != getIP().GetPosition()) {
9502     getIP().Set(else_head);
9503   } else if (endif_head.GetPosition() != getIP().GetPosition()) {
9504     getIP().Set(endif_head);
9505   } else {
9506     // No else or endif.  Advance past the next instruction (as normal).
9507     getIP().Advance();
9508   }
9509 }
9510 
9511 
9512 /*! The only way that this instruction can be executed is if the if passed, or
9513  if there was no if.  In both cases, we're going to jump to the first <end-if>, or
9514  skip one instruction.
9515  */
Inst_Else(cAvidaContext & ctx)9516 bool cHardwareCPU::Inst_Else(cAvidaContext& ctx)
9517 {
9518   cHeadCPU endif_head = Find("endif");
9519   if (endif_head.GetPosition() != getIP().GetPosition()) {
9520     // If the <end-if> is somewhere else, jump to it.
9521     getIP().Set(endif_head);
9522   } else {
9523     // Otherwise, just skip one instruction.
9524     getIP().Advance();
9525   }
9526 
9527   return true;
9528 }
9529 
9530 /*! This is just a placeholder; it has no functionality of its own.
9531  */
Inst_EndIf(cAvidaContext & ctx)9532 bool cHardwareCPU::Inst_EndIf(cAvidaContext& ctx) {
9533   return true;
9534 }
9535 
9536 
9537 /*! A generic broadcast method, to simplify the development of different range
9538  broadcasts.
9539  */
BroadcastX(cAvidaContext & ctx,int depth)9540 bool cHardwareCPU::BroadcastX(cAvidaContext& ctx, int depth)
9541 {
9542   const int label_reg = FindModifiedRegister(REG_BX);
9543   const int data_reg = FindNextRegister(label_reg);
9544 
9545   cOrgMessage msg = cOrgMessage(m_organism);
9546   msg.SetLabel(GetRegister(label_reg));
9547   msg.SetData(GetRegister(data_reg));
9548   return m_organism->BroadcastMessage(ctx, msg, depth);
9549 }
9550 
9551 
9552 /*! A single-hop broadcast instruction - send a message to all 1-hop neighbors
9553  of this organism.
9554  */
Inst_Broadcast1(cAvidaContext & ctx)9555 bool cHardwareCPU::Inst_Broadcast1(cAvidaContext& ctx) {
9556   return BroadcastX(ctx, 1);
9557 }
9558 
9559 
9560 /*! A double-hop broadcast instruction - send a message to all 2-hop neighbors
9561  of this organism.
9562  */
Inst_Broadcast2(cAvidaContext & ctx)9563 bool cHardwareCPU::Inst_Broadcast2(cAvidaContext& ctx) {
9564   return BroadcastX(ctx, 2);
9565 }
9566 
9567 
9568 /*! Another broadcast instruction variant - send a message to all 4-hop neighbors
9569  of this organism.
9570  */
Inst_Broadcast4(cAvidaContext & ctx)9571 bool cHardwareCPU::Inst_Broadcast4(cAvidaContext& ctx) {
9572   return BroadcastX(ctx, 4);
9573 }
9574 
9575 
9576 /*! Another broadcast instruction variant - send a message to all 8-hop neighbors
9577  of this organism.
9578  */
Inst_Broadcast8(cAvidaContext & ctx)9579 bool cHardwareCPU::Inst_Broadcast8(cAvidaContext& ctx) {
9580   return BroadcastX(ctx, 8);
9581 }
9582 
9583 
9584 
9585 /* Donate if the neighbor previously donated to the organism. */
Inst_DonateIfDonor(cAvidaContext & ctx)9586 bool cHardwareCPU::Inst_DonateIfDonor(cAvidaContext& ctx)
9587 {
9588   cOrganism * neighbor = m_organism->GetNeighbor();
9589   if (neighbor != NULL) {
9590     // check if the neighbor was a donor
9591     if (m_organism->IsDonor(neighbor->GetID())) {
9592       m_world->GetStats().IncDonateToDonor();
9593       Inst_DonateFacingRawMaterialsOtherSpecies(ctx);
9594     }
9595   }
9596 
9597   return true;
9598 }
9599 
9600 /* Donate raw materials (of one kind) to a neighbor, but
9601  only if the neighbor is of a different species. If the
9602  instruction fails, there is no consequence. */
Inst_DonateFacingRawMaterialsOtherSpecies(cAvidaContext & ctx)9603 bool cHardwareCPU::Inst_DonateFacingRawMaterialsOtherSpecies(cAvidaContext& ctx)
9604 {
9605   cOrganism * neighbor = m_organism->GetNeighbor();
9606   if (neighbor != NULL) {
9607 
9608     int spec_self =  m_organism->GetLineageLabel();
9609     int spec_neighbor = neighbor->GetLineageLabel();
9610 
9611     if (spec_self != spec_neighbor) {
9612       Inst_DonateFacingString(ctx);
9613     }
9614   }
9615   return true;
9616 }
9617 
9618 /* Donate a string that you have produced to the facing organism */
Inst_DonateFacingString(cAvidaContext & ctx)9619 bool cHardwareCPU::Inst_DonateFacingString(cAvidaContext& ctx)
9620 {
9621   // Get faced neighbor
9622   cOrganism * neighbor = m_organism->GetNeighbor();
9623   int cost = m_world->GetConfig().ALT_COST.Get();
9624   int my_string = m_organism->GetLineageLabel();
9625 
9626   // Donate only if we have found a neighbor.
9627   if (neighbor != NULL) {
9628 
9629     // Check if the organism has enough of this string on hand.
9630     if ((m_organism->GetNumberStringsOnHand(my_string) >= cost) && (neighbor->CanReceiveString(my_string, cost))) {
9631 
9632       // sometimes the donation will fail.
9633       // get the probability of failure
9634       unsigned int prob_fail = m_world->GetConfig().DONATION_FAILURE_PERCENT.Get();
9635       unsigned int rand_num = m_world->GetRandom().GetUInt(0, 100);
9636       // neighbor donates to organism.
9637       if (rand_num < prob_fail) {
9638 	// EXIT
9639 	return true;
9640       }
9641 
9642       m_organism->DonateString(my_string, cost);
9643       neighbor->AddOtherRawMaterials(cost, m_organism->GetID());
9644       neighbor->ReceiveString(my_string, cost, m_organism->GetID());
9645       neighbor->AddDonatedLineage(m_organism->GetLineageLabel());
9646 
9647       // track stats
9648       m_organism->Donated();
9649 
9650       ComputeReputation();
9651     }
9652   }
9653   return true;
9654 }
9655 
9656 /* Donate raw materials to the facing organism. */
Inst_DonateFacingRawMaterials(cAvidaContext & ctx)9657 bool cHardwareCPU::Inst_DonateFacingRawMaterials(cAvidaContext& ctx)
9658 {
9659 
9660   // Get faced neighbor
9661   cOrganism * neighbor = m_organism->GetNeighbor();
9662   int cost = m_world->GetConfig().ALT_COST.Get();
9663 
9664   // Donate only if we have found a neighbor.
9665   if (neighbor != NULL) {
9666 
9667     // Subtract raw materials from the organism (currently subtracts 1 resource...)
9668     // fails if the organism does not have any more resources
9669     if (m_organism->SubtractSelfRawMaterials(cost)) {
9670 
9671       // sometimes the donation will fail.
9672       // get the probability of failure
9673       unsigned int prob_fail = m_world->GetConfig().DONATION_FAILURE_PERCENT.Get();
9674       unsigned int rand_num = m_world->GetRandom().GetUInt(0, 100);
9675       // neighbor donates to organism.
9676       if (rand_num < prob_fail) {
9677 	// EXIT
9678 	return true;
9679       }
9680 
9681       neighbor->AddOtherRawMaterials(cost, m_organism->GetID());
9682       neighbor->AddDonatedLineage(m_organism->GetLineageLabel());
9683 
9684       // rotate recipient to face donor
9685       // by rotating until the recipient faces the donor
9686       // adding a new comment.
9687       if (m_world->GetConfig().ROTATE_ON_DONATE.Get()) {
9688 	while (neighbor->GetNeighbor() != m_organism) {
9689 	  neighbor->Rotate(1);
9690 	}
9691       }
9692 
9693       // track stats
9694       m_organism->Donated();
9695 
9696       ComputeReputation();
9697 
9698     }
9699   }
9700   return true;
9701 }
9702 
9703 
9704 
9705 /* An organism artificially increases its reputation without donating. */
Inst_Pose(cAvidaContext & ctx)9706 bool cHardwareCPU::Inst_Pose(cAvidaContext& ctx)
9707 {
9708   // update reputation to include this phony donation.
9709   // get the current reputation; increment by 1.
9710   m_organism->SetReputation(m_organism->GetReputation() + 1);
9711 
9712   return true;
9713 }
9714 
9715 
9716 
9717 /*! An organism's reputation is stored as an opinion. This instruction
9718  uses Inst_GetNeighborsOpinion to do the heavy lifting, but includes
9719  default behavior suitable for reputations. Specifically, if an
9720  neighbor has no reputation (i.e., it has not donated) or does not
9721  exist, then this instruction puts zeros into the registers.
9722  */
Inst_GetNeighborsReputation(cAvidaContext & ctx)9723 bool cHardwareCPU::Inst_GetNeighborsReputation(cAvidaContext& ctx)
9724 {
9725   // Get faced neighbor
9726   cOrganism * neighbor = m_organism->GetNeighbor();
9727   if (neighbor != NULL) {
9728     const int raw_mat_reg = FindModifiedRegister(REG_AX);
9729     GetRegister(raw_mat_reg) = neighbor->GetReputation();
9730   }
9731   return true;
9732 }
9733 
9734 
9735 /*! An organism's reputation is stored as an opinion. This instruction
9736  uses Inst_GetOpinion to do the heavy lifting, but includes
9737  default behavior suitable for reputations. Specifically, if an
9738  organism has no reputation (i.e., it has not donated), then this
9739  instruction puts zeros into the registers.
9740  */
Inst_GetReputation(cAvidaContext & ctx)9741 bool cHardwareCPU::Inst_GetReputation(cAvidaContext& ctx)
9742 {
9743   const int opinion_reg = FindModifiedRegister(REG_BX);
9744   GetRegister(opinion_reg) = m_organism->GetReputation();
9745   return true;
9746 }
9747 
9748 /* Sense the number of raw materials an organism has. Store in
9749  ?REG_AX? */
Inst_GetAmountOfRawMaterials(cAvidaContext & ctx)9750 bool cHardwareCPU::Inst_GetAmountOfRawMaterials(cAvidaContext& ctx)
9751 {
9752   const int raw_mat_reg = FindModifiedRegister(REG_AX);
9753   GetRegister(raw_mat_reg) = m_organism->GetNumberStringsOnHand(0);
9754   return true;
9755 }
9756 
9757 /* Sense the number of raw materials an organism has. Store in
9758  ?REG_BX? */
Inst_GetAmountOfOtherRawMaterials(cAvidaContext & ctx)9759 bool cHardwareCPU::Inst_GetAmountOfOtherRawMaterials(cAvidaContext& ctx)
9760 {
9761   const int raw_mat_reg = FindModifiedRegister(REG_BX);
9762   GetRegister(raw_mat_reg) = m_organism->GetNumberStringsOnHand(1);
9763   return true;
9764 }
9765 
9766 
9767 
9768 /* Rotate to face the organism with the highest reputation */
Inst_RotateToGreatestReputation(cAvidaContext & ctx)9769 bool cHardwareCPU::Inst_RotateToGreatestReputation(cAvidaContext& ctx)
9770 {
9771   m_organism->GetOrgInterface().RotateToGreatestReputation();
9772 
9773   return true;
9774 }
9775 
9776 /* Rotate to face the organism with the highest reputation that has
9777  a different tag. */
Inst_RotateToGreatestReputationWithDifferentTag(cAvidaContext & ctx)9778 bool cHardwareCPU::Inst_RotateToGreatestReputationWithDifferentTag(cAvidaContext& ctx)
9779 {
9780   m_organism->GetOrgInterface().RotateToGreatestReputationWithDifferentTag(m_organism->GetTagLabel());
9781   return true;
9782 }
9783 
9784 /* Rotate to face the organism with the highest reputation that has
9785  a different lineage. */
Inst_RotateToGreatestReputationWithDifferentLineage(cAvidaContext & ctx)9786 bool cHardwareCPU::Inst_RotateToGreatestReputationWithDifferentLineage(cAvidaContext& ctx)
9787 {
9788   m_organism->GetOrgInterface().RotateToGreatestReputationWithDifferentLineage(m_organism->GetLineageLabel());
9789   return true;
9790 }
9791 
9792 
9793 /* Rotate to face the organism with the highest reputation and then
9794  immediately donate */
Inst_RotateToGreatestReputationAndDonate(cAvidaContext & ctx)9795 bool cHardwareCPU::Inst_RotateToGreatestReputationAndDonate(cAvidaContext& ctx)
9796 {
9797   Inst_RotateToGreatestReputation(ctx);
9798   Inst_DonateFacingRawMaterials(ctx);
9799 
9800   return true;
9801 }
9802 
9803 
9804 
Inst_RotateToDifferentTag(cAvidaContext & ctx)9805 bool cHardwareCPU::Inst_RotateToDifferentTag(cAvidaContext& ctx)
9806 {
9807   //get the neighborhood size
9808   const int num_neighbors = m_organism->GetNeighborhoodSize();
9809 
9810   // Turn to face a random neighbor
9811   int neighbor_id = ctx.GetRandom().GetInt(num_neighbors);
9812   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(1);
9813   cOrganism * neighbor = m_organism->GetNeighbor();
9814 
9815   int max_id = neighbor_id + num_neighbors;
9816 
9817   //we have not found a match yet
9818   bool found = false;
9819 
9820   // rotate through orgs in neighborhood
9821   while (neighbor_id < max_id) {
9822     neighbor = m_organism->GetNeighbor();
9823 
9824     //if neighbor exists, do they have a different tag?
9825     if (neighbor != NULL) {
9826       if (m_organism->GetTagLabel() != neighbor->GetTagLabel()) found = true;
9827     }
9828 
9829     // stop searching through the neighbors if we already found one
9830     if (found == true) {
9831       break;
9832     }
9833 
9834     m_organism->Rotate(1);
9835     neighbor_id++;
9836   }
9837 
9838   return true;
9839 }
9840 
9841 
9842 
9843 /* Execute the next instruction if the neighbor was a donor. */
Inst_IfDonor(cAvidaContext & ctx)9844 bool cHardwareCPU::Inst_IfDonor(cAvidaContext& ctx)
9845 {
9846   bool donor = false;
9847   cOrganism * neighbor = m_organism->GetNeighbor();
9848   if (neighbor != NULL) {
9849     // check if the neighbor was a donor
9850     if (m_organism->IsDonor(neighbor->GetID())) {
9851       donor = true;
9852     }
9853   }
9854   if (!donor)  getIP().Advance();
9855 
9856   return true;
9857 }
9858 
9859 
ComputeReputation()9860 void cHardwareCPU::ComputeReputation()
9861 {
9862   cOrganism * neighbor = m_organism->GetNeighbor();
9863 
9864   // update reputation to include this donation.
9865   // get the current reputation; increment by 1.
9866   // includes a concept of standing
9867   if (m_world->GetConfig().AUTO_REPUTATION.Get() == 1) {
9868     int my_rep = m_organism->GetReputation();
9869     m_organism->SetReputation(my_rep +1);
9870     // get neighbor reputation
9871     int rep = neighbor->GetReputation();
9872     // if the organism has not yet donated, put it into bad standing
9873     if (rep == 0) neighbor->SetReputation(-1);
9874   } else if (m_world->GetConfig().AUTO_REPUTATION.Get() == 2) {
9875     // reputation is proportional to how much you have donated/received
9876     int my_rep = m_organism->GetReputation();
9877     m_organism->SetReputation(my_rep +1);
9878     // get neighbor reputation
9879     int rep = neighbor->GetReputation();
9880     neighbor->SetReputation(rep-1);
9881   } else if (m_world->GetConfig().AUTO_REPUTATION.Get() == 3)  {
9882     // set rep to 1, since the organism donated
9883     m_organism->SetReputation(1);
9884     // get neighbor reputation
9885     int rep = neighbor->GetReputation();
9886     // if the organism has not yet donated, put it into bad standing
9887     if (rep == 0) neighbor->SetReputation(-1);
9888   } else if (m_world->GetConfig().AUTO_REPUTATION.Get() == 4) {
9889     // Similar to 1, except does not include standing.
9890     int my_rep = m_organism->GetReputation();
9891     m_organism->SetReputation(my_rep +1);
9892   }
9893 }
9894 
9895 
9896 
9897 /* Check if the string in the organisms buffer corresponds to the
9898  string it is producing. If so, -1 out the buffer and increment the
9899  number of raw materials the organism has. Otherwise, do nothing. */
9900 
Inst_ProduceString(cAvidaContext & ctx)9901 bool cHardwareCPU::Inst_ProduceString(cAvidaContext& ctx)
9902 {
9903   int num = 0;
9904   int max_num = 0;
9905   int max_string = -1;
9906   int string_size = 0;
9907   bool val;
9908 
9909   m_organism->InitStringMap();
9910 
9911   // Figure out if it has produced any of the strings
9912   std::vector < cString > temp_strings = m_world->GetEnvironment().GetMatchStringsFromTask();
9913   if (temp_strings.size()) string_size = temp_strings[0].GetSize();
9914   for (unsigned int i=0; i < temp_strings.size(); i++){
9915     num = m_organism->MatchOutputBuffer(temp_strings[i]);
9916     if (num > max_num) {
9917       max_num = num;
9918       max_string = i;
9919     }
9920   }
9921 
9922   // Determine if it has to produce one in particular.
9923   if (m_world->GetConfig().SPECIALISTS.Get()) {
9924     if (m_organism->GetLineageLabel() != max_string) {
9925       max_num = 0;
9926     }
9927   }
9928 
9929   // If still ok, add the raw material and clear the buffer
9930   if (max_num == string_size) {
9931     // Indicate organism has produced the string
9932     val = m_organism->ProduceString(max_string);
9933 
9934     // temp until old code is phased out:
9935     m_organism->AddSelfRawMaterials(1);
9936 
9937     // Clear buffer if the organism has received credit for the string
9938     if (val) m_organism->SetOutputNegative1();
9939   }
9940 
9941   return true;
9942 }
9943 
9944 //! An organism joins a group by setting it opinion to the group id.
Inst_JoinGroup(cAvidaContext & ctx)9945 bool cHardwareCPU::Inst_JoinGroup(cAvidaContext& ctx)
9946 {
9947   int opinion = m_world->GetConfig().DEFAULT_GROUP.Get();
9948   // Check if the org is currently part of a group
9949   assert(m_organism != 0);
9950 
9951   int prop_group_id = GetRegister(FindModifiedRegister(REG_BX));
9952 
9953   // check if this is a valid group
9954   if (m_world->GetConfig().USE_FORM_GROUPS.Get() == 2 &&
9955     !(m_world->GetEnvironment().IsGroupID(prop_group_id))) return false;
9956 
9957   // injected orgs might not have an opinion
9958   if (m_organism->GetOrgInterface().HasOpinion(m_organism)) {
9959     opinion = m_organism->GetOpinion().first;
9960 
9961     //return false if org setting opinion to current one (avoid paying costs for not switching)
9962     if (opinion == prop_group_id) return false;
9963 
9964     // A random chance for failure to join group based on config.
9965     if (m_world->GetConfig().JOIN_GROUP_FAILURE.Get() != 0) {
9966       int percent_failure = m_world->GetConfig().JOIN_GROUP_FAILURE.Get();
9967       double prob_failure = abs((double) percent_failure / 100.0);
9968       double rand = m_world->GetRandom().GetDouble();
9969       if (rand <= prob_failure && percent_failure > 0) return true;
9970       else if (rand <= prob_failure && percent_failure < 0) {
9971         m_organism->Die(ctx);
9972         return true;
9973       }
9974     }
9975 
9976     // If tolerances are on the org must pass immigration chance
9977     if (m_world->GetConfig().TOLERANCE_WINDOW.Get() > 0) {
9978       m_organism->GetOrgInterface().AttemptImmigrateGroup(prop_group_id, m_organism);
9979       return true;
9980     }
9981     else {
9982       // otherwise, subtract org from current group
9983       m_organism->LeaveGroup(opinion);
9984     }
9985   }
9986 
9987   // Set the opinion
9988   m_organism->GetOrgInterface().SetOpinion(prop_group_id, m_organism);
9989 
9990   // Add org to group count
9991   if (m_organism->GetOrgInterface().HasOpinion(m_organism)) {
9992     opinion = m_organism->GetOpinion().first;
9993     m_organism->JoinGroup(opinion);
9994   }
9995   return true;
9996 }
9997 
Inst_JoinMTGroup(cAvidaContext & ctx)9998 bool cHardwareCPU::Inst_JoinMTGroup(cAvidaContext& ctx)
9999 {
10000   if (m_organism->GetPhenotype().GetMatingType() == MATING_TYPE_JUVENILE) return false;
10001   return Inst_JoinGroup(ctx);
10002 }
10003 
10004 /* Must be nop-modified.
10005  * Moves organism +1 group if the nop-register has a positive number,
10006  * moves organism -1 group if the nop-register has a negative number,
10007  * wraps from the top group back to group 1 (skipping 0).
10008  */
Inst_JoinNextGroup(cAvidaContext & ctx)10009 bool cHardwareCPU::Inst_JoinNextGroup(cAvidaContext& ctx)
10010 {
10011   // Check for an opinion.
10012   if (!m_organism->GetOrgInterface().HasOpinion(m_organism)) return false;
10013 
10014   if (m_world->GetConfig().USE_FORM_GROUPS.Get() != 2) return false;
10015 
10016   // There must be more than the org's current group and the 0 group, which is skipped.
10017   int num_groups = 0;
10018   std::set<int> fts_avail = m_world->GetEnvironment().GetGroupIDs();
10019   set <int>::iterator itr;
10020   for (itr = fts_avail.begin();itr!=fts_avail.end();itr++) num_groups++;
10021 
10022   if (num_groups <= 2) return false;
10023 
10024   // If not nop-modified, fails to execute.
10025   if (!(m_inst_set->IsNop(getIP().GetNextInst()))) return false;
10026   // Retrieves the value from the nop-modifying register.
10027   const int nop_reg = FindModifiedRegister(REG_BX);
10028   int reg_value = GetRegister(nop_reg);
10029   // If no group change
10030   if (reg_value == 0) return false;
10031 
10032   // A random chance for failure to join group based on config.
10033   if (m_world->GetConfig().JOIN_GROUP_FAILURE.Get() != 0) {
10034     int percent_failure = m_world->GetConfig().JOIN_GROUP_FAILURE.Get();
10035     double prob_failure = abs((double) percent_failure / 100.0);
10036     double rand = m_world->GetRandom().GetDouble();
10037     if (rand <= prob_failure && percent_failure > 0) return true;
10038     else if (rand <= prob_failure && percent_failure < 0) {
10039       m_organism->Die(ctx);
10040       return true;
10041     }
10042   }
10043 
10044   int opinion = m_organism->GetOpinion().first;
10045   int new_opinion = -1;
10046   if (opinion == (num_groups - 1)) {
10047     if (reg_value > 0) {
10048       new_opinion = 1;
10049     }
10050     else if (reg_value < 0) {
10051       new_opinion = opinion - 1;
10052     }
10053   }
10054   else if ((opinion == 1) || (opinion == 0)) {
10055     if (reg_value > 0) {
10056       new_opinion = opinion + 1;
10057     }
10058     else if (reg_value < 0) {
10059       new_opinion = num_groups - 1;
10060     }
10061   }
10062   else if ((opinion != (num_groups - 1)) && (opinion != 1) && (opinion != 0)) {
10063     if (reg_value > 0) {
10064       new_opinion = opinion + 1;
10065     }
10066     else if (reg_value < 0) {
10067       new_opinion = opinion - 1;
10068     }
10069   }
10070   if (new_opinion == -1) return false;
10071 
10072   if (m_world->GetConfig().TOLERANCE_WINDOW.Get() > 0) {
10073     m_organism->GetOrgInterface().AttemptImmigrateGroup(new_opinion, m_organism);
10074   }
10075   else {
10076     m_organism->GetOrgInterface().SetOpinion(new_opinion, m_organism);
10077     m_organism->LeaveGroup(opinion);
10078     m_organism->JoinGroup(new_opinion);
10079   }
10080   return true;
10081 }
10082 
Inst_JoinNextMTGroup(cAvidaContext & ctx)10083 bool cHardwareCPU::Inst_JoinNextMTGroup(cAvidaContext& ctx)
10084 {
10085   if (m_organism->GetPhenotype().GetMatingType() == MATING_TYPE_JUVENILE) return false;
10086   return Inst_JoinNextGroup(ctx);
10087 }
10088 
10089 //! Gets the number of organisms in the current organism's group
10090 //! and places the value in the ?BX? register
Inst_NumberOrgsInMyGroup(cAvidaContext & ctx)10091 bool cHardwareCPU::Inst_NumberOrgsInMyGroup(cAvidaContext& ctx)
10092 {
10093   assert(m_organism != 0);
10094 
10095   int num_orgs = 0;
10096   if (m_organism->GetOrgInterface().HasOpinion(m_organism)) {
10097     int opinion = m_organism->GetOpinion().first;
10098     num_orgs = m_organism->GetOrgInterface().NumberOfOrganismsInGroup(opinion);
10099   }
10100   const int num_org_reg = FindModifiedRegister(REG_BX);
10101   GetRegister(num_org_reg) = num_orgs;
10102   return true;
10103 }
10104 
Inst_NumberMTInMyGroup(cAvidaContext & ctx)10105 bool cHardwareCPU::Inst_NumberMTInMyGroup(cAvidaContext& ctx)
10106 {
10107   assert(m_organism != 0);
10108   if (m_organism->GetPhenotype().GetMatingType() == MATING_TYPE_JUVENILE) return false;
10109 
10110   int num_fem = 0;
10111   int num_male = 0;
10112   int num_juv = 0;
10113   if (m_organism->GetOrgInterface().HasOpinion(m_organism)) {
10114     int opinion = m_organism->GetOpinion().first;
10115     num_fem = m_organism->GetOrgInterface().NumberGroupFemales(opinion);
10116     num_male = m_organism->GetOrgInterface().NumberGroupMales(opinion);
10117     num_juv = m_organism->GetOrgInterface().NumberGroupJuvs(opinion);
10118   }
10119   const int reg1 = FindModifiedRegister(REG_BX);
10120   const int reg2 = FindModifiedNextRegister(reg1);
10121   const int reg3 = FindModifiedNextRegister(reg2);
10122   GetRegister(reg1) = num_fem;
10123   GetRegister(reg2) = num_male;
10124   GetRegister(reg3) = num_juv;
10125   return true;
10126 }
10127 
10128 //! Gets the number of organisms in the group of a given id
10129 //! specified by the ?BX? register and places the value in the ?CX? register
Inst_NumberOrgsInGroup(cAvidaContext & ctx)10130 bool cHardwareCPU::Inst_NumberOrgsInGroup(cAvidaContext& ctx)
10131 {
10132   assert(m_organism != 0);
10133   const int group_id = FindModifiedRegister(REG_BX);
10134   const int num_org_reg = FindModifiedRegister(REG_CX);
10135 
10136   int num_orgs = m_organism->GetOrgInterface().NumberOfOrganismsInGroup(group_id);
10137   GetRegister(num_org_reg) = num_orgs;
10138   return true;
10139 }
10140 
Inst_NumberMTInGroup(cAvidaContext & ctx)10141 bool cHardwareCPU::Inst_NumberMTInGroup(cAvidaContext& ctx)
10142 {
10143   assert(m_organism != 0);
10144   if (m_organism->GetPhenotype().GetMatingType() == MATING_TYPE_JUVENILE) return false;
10145 
10146   const int group_id = FindModifiedRegister(REG_BX);
10147 
10148   int num_fem = m_organism->GetOrgInterface().NumberGroupFemales(group_id);
10149   int num_male = m_organism->GetOrgInterface().NumberGroupMales(group_id);
10150   int num_juv = m_organism->GetOrgInterface().NumberGroupJuvs(group_id);
10151   const int reg1 = FindModifiedRegister(REG_BX);
10152   const int reg2 = FindModifiedNextRegister(reg1);
10153   const int reg3 = FindModifiedNextRegister(reg2);
10154   GetRegister(reg1) = num_fem;
10155   GetRegister(reg2) = num_male;
10156   GetRegister(reg3) = num_juv;
10157   return true;
10158 }
10159 
10160 
10161 /* Must be nop-modified.
10162  Places the number of orgs in the +1 group in the BX register, if the nop-modifying register is positive,
10163  places the number of orgs in the -1 group in the BX register, if the nop-modifying register is negative,
10164  wraps from the top group back to group 1 (skipping 0).
10165  */
Inst_NumberNextGroup(cAvidaContext & ctx)10166 bool cHardwareCPU::Inst_NumberNextGroup(cAvidaContext& ctx)
10167 {
10168   // Check for an opinion.
10169   if (!m_organism->GetOrgInterface().HasOpinion(m_organism)) return false;
10170 
10171   if (m_world->GetConfig().USE_FORM_GROUPS.Get() != 2) return false;
10172   int opinion = m_organism->GetOpinion().first;
10173 
10174   const int num_groups = m_organism->GetOrgInterface().GetResources(ctx).GetSize();
10175   if (num_groups <= 2) return false;
10176 
10177   // If not nop-modified, fails to execute.
10178   if (!(m_inst_set->IsNop(getIP().GetNextInst()))) return false;
10179   // Retrieves the value from the nop-modifying register.
10180   const int nop_reg = FindModifiedRegister(REG_BX);
10181   int reg_value = GetRegister(nop_reg);
10182   // If no group change
10183   if (reg_value == 0) return false;
10184 
10185   int query_group = opinion;
10186 
10187   if (opinion == (num_groups - 1)) {
10188     if (reg_value > 0) query_group = 1;
10189     else if (reg_value < 0) query_group = opinion - 1;
10190   }
10191   else if ((opinion == 1) || (opinion == 0)) {
10192     if (reg_value > 0) query_group = opinion + 1;
10193     else if (reg_value < 0) query_group = num_groups - 1;
10194   }
10195   else if ((opinion != (num_groups - 1)) && (opinion != 1) && (opinion != 0)) {
10196     if (reg_value > 0) query_group = opinion + 1;
10197     else if (reg_value < 0) query_group = opinion - 1;
10198   }
10199 
10200   GetRegister(REG_BX) = m_organism->GetOrgInterface().NumberOfOrganismsInGroup(query_group);
10201 
10202   return true;
10203 }
10204 
Inst_NumberMTNextGroup(cAvidaContext & ctx)10205 bool cHardwareCPU::Inst_NumberMTNextGroup(cAvidaContext& ctx)
10206 {
10207   if (m_organism->GetPhenotype().GetMatingType() == MATING_TYPE_JUVENILE) return false;
10208 
10209   // Check for an opinion.
10210   if (!m_organism->GetOrgInterface().HasOpinion(m_organism)) return false;
10211 
10212   if (m_world->GetConfig().USE_FORM_GROUPS.Get() != 2) return false;
10213   int opinion = m_organism->GetOpinion().first;
10214 
10215   const int num_groups = m_organism->GetOrgInterface().GetResources(ctx).GetSize();
10216   if (num_groups <= 2) return false;
10217 
10218   // If not nop-modified, fails to execute.
10219   if (!(m_inst_set->IsNop(getIP().GetNextInst()))) return false;
10220   // Retrieves the value from the nop-modifying register.
10221   const int nop_reg = FindModifiedRegister(REG_BX);
10222   int reg_value = GetRegister(nop_reg);
10223   // If no group change
10224   if (reg_value == 0) return false;
10225 
10226   int query_group = opinion;
10227 
10228   if (opinion == (num_groups - 1)) {
10229     if (reg_value > 0) query_group = 1;
10230     else if (reg_value < 0) query_group = opinion - 1;
10231   }
10232   else if ((opinion == 1) || (opinion == 0)) {
10233     if (reg_value > 0) query_group = opinion + 1;
10234     else if (reg_value < 0) query_group = num_groups - 1;
10235   }
10236   else if ((opinion != (num_groups - 1)) && (opinion != 1) && (opinion != 0)) {
10237     if (reg_value > 0) query_group = opinion + 1;
10238     else if (reg_value < 0) query_group = opinion - 1;
10239   }
10240 
10241   int num_fem = m_organism->GetOrgInterface().NumberGroupFemales(query_group);
10242   int num_male = m_organism->GetOrgInterface().NumberGroupMales(query_group);
10243   int num_juv = m_organism->GetOrgInterface().NumberGroupJuvs(query_group);
10244   const int reg1 = FindModifiedRegister(REG_BX);
10245   const int reg2 = FindModifiedNextRegister(reg1);
10246   const int reg3 = FindModifiedNextRegister(reg2);
10247   GetRegister(reg1) = num_fem;
10248   GetRegister(reg2) = num_male;
10249   GetRegister(reg3) = num_juv;
10250 
10251   return true;
10252 }
10253 
10254 //Kill some other random organism in group
Inst_KillGroupMember(cAvidaContext & ctx)10255 bool cHardwareCPU::Inst_KillGroupMember(cAvidaContext& ctx)
10256 {
10257   int opinion;
10258   // Check if the org is currently part of a group
10259   assert(m_organism != 0);
10260 
10261   if (m_organism->GetOrgInterface().HasOpinion(m_organism)) {
10262     opinion = m_organism->GetOpinion().first;
10263     // Kill organism in group
10264     m_world->GetPopulation().KillGroupMember(ctx, opinion, m_organism);
10265   }
10266   return true;
10267 }
10268 
10269 /* Increases tolerance towards the addition of members to the group:
10270  nop-A: increases tolerance towards immigrants
10271  nop-B: increases tolerance towards own offspring
10272  nop-C: increases tolerance towards other offspring of the group.
10273  Removes the record of a previous update when dec-tolerance was executed,
10274  and places the modified tolerance total in the BX register.
10275  */
Inst_IncTolerance(cAvidaContext & ctx)10276 bool cHardwareCPU::Inst_IncTolerance(cAvidaContext& ctx)
10277 {
10278   // Exit if tolerance is not enabled
10279   if (!m_world->GetConfig().USE_FORM_GROUPS.Get()) return false;
10280   if (m_world->GetConfig().TOLERANCE_WINDOW.Get() <= 0) return false;
10281   // Exit if organism is not in a group
10282   if (!m_organism->GetOrgInterface().HasOpinion(m_organism)) return false;
10283   // Exit if the instruction is not nop-modified
10284   if (!m_inst_set->IsNop(getIP().GetNextInst())) return false;
10285 
10286   int toleranceType = 0;
10287   if (m_world->GetConfig().TOLERANCE_VARIATIONS.Get() == 0) {
10288     const int tolerance_to_modify = FindModifiedRegister(REG_BX);
10289 
10290     toleranceType = -1;
10291     if (tolerance_to_modify == REG_AX) toleranceType = 0;
10292     else if (tolerance_to_modify == REG_BX) toleranceType = 1;
10293     else if (tolerance_to_modify == REG_CX) toleranceType = 2;
10294 
10295     // Not a recognized register
10296     if (toleranceType == -1) return false;
10297   }
10298 
10299   // Update the tolerance and store the result in register B
10300   int result = m_organism->GetOrgInterface().IncTolerance(toleranceType, ctx);
10301   if (result == -1) return false;
10302   GetRegister(REG_BX) = result;
10303   return true;
10304 }
10305 
10306 /* Decreases tolerance towards the addition of members to the group,
10307  nop-A: decreases tolerance towards immigrants
10308  nop-B: decreases tolerance towards own offspring
10309  nop-C: decreases tolerance towards other offspring of the group.
10310  Adds to records the update during which dec-tolerance was executed,
10311  and places the modified tolerance total in the BX register.
10312  */
Inst_DecTolerance(cAvidaContext & ctx)10313 bool cHardwareCPU::Inst_DecTolerance(cAvidaContext& ctx)
10314 {
10315   // Exit if tolerance is not enabled
10316   if (!m_world->GetConfig().USE_FORM_GROUPS.Get()) return false;
10317   if (m_world->GetConfig().TOLERANCE_WINDOW.Get() <= 0) return false;
10318   // Exit if organism is not in a group
10319   if (!m_organism->GetOrgInterface().HasOpinion(m_organism)) return false;
10320   // Exit if the instruction is not nop-modified
10321   if (!m_inst_set->IsNop(getIP().GetNextInst())) return false;
10322 
10323   int toleranceType = 0;
10324   if (m_world->GetConfig().TOLERANCE_VARIATIONS.Get() == 0) {
10325     const int tolerance_to_modify = FindModifiedRegister(REG_BX);
10326 
10327     toleranceType = -1;
10328     if (tolerance_to_modify == REG_AX) toleranceType = 0;
10329     else if (tolerance_to_modify == REG_BX) toleranceType = 1;
10330     else if (tolerance_to_modify == REG_CX) toleranceType = 2;
10331 
10332     // Not a recognized register
10333     if (toleranceType == -1) return false;
10334   }
10335 
10336   // Update the tolerance and store the result in register B
10337   GetRegister(REG_BX) = m_organism->GetOrgInterface().DecTolerance(toleranceType, ctx);
10338   return true;
10339 }
10340 
10341 /* Retrieve current tolerance levels, placing each tolerance in a different register.
10342  Register AX: tolerance towards immigrants
10343  Register BX: tolerance towards own offspring
10344  Register CX: tolerance towards other offspring in the group
10345  */
Inst_GetTolerance(cAvidaContext & ctx)10346 bool cHardwareCPU::Inst_GetTolerance(cAvidaContext& ctx)
10347 {
10348   bool exec_success = false;
10349   if (m_world->GetConfig().USE_FORM_GROUPS.Get() && m_world->GetConfig().TOLERANCE_WINDOW.Get() > 0) {
10350     if(m_organism->GetOrgInterface().HasOpinion(m_organism)) {
10351       m_organism->GetOrgInterface().PushToleranceInstExe(6, ctx);
10352 
10353       int tolerance_immigrants = m_organism->GetPhenotype().CalcToleranceImmigrants();
10354       int tolerance_own = m_organism->GetPhenotype().CalcToleranceOffspringOwn();
10355       int tolerance_others = m_organism->GetPhenotype().CalcToleranceOffspringOthers();
10356       GetRegister(REG_AX) = tolerance_immigrants;
10357       GetRegister(REG_BX) = tolerance_own;
10358       GetRegister(REG_CX) = tolerance_others;
10359       exec_success = true;
10360     }
10361   }
10362   return exec_success;
10363 }
10364 
10365 /* Retrieve group tolerances placing each in a different register.
10366  Register AX: group tolerance towards immigrants
10367  Register BX: group tolerance towards own offspring
10368  Register CX: group tolerance towards offspring
10369  */
Inst_GetGroupTolerance(cAvidaContext & ctx)10370 bool cHardwareCPU::Inst_GetGroupTolerance(cAvidaContext& ctx)
10371 {
10372   bool exec_success = false;
10373   // If groups are used and tolerances are on...
10374   if (m_world->GetConfig().USE_FORM_GROUPS.Get() && m_world->GetConfig().TOLERANCE_WINDOW.Get() > 0) {
10375     if (m_organism->GetOrgInterface().HasOpinion(m_organism)) {
10376       m_organism->GetOrgInterface().PushToleranceInstExe(7, ctx);
10377 
10378       const int group_id = m_organism->GetOpinion().first;
10379 
10380       int mating_type = -1;
10381       if (m_world->GetConfig().TOLERANCE_VARIATIONS.Get() == 2) {
10382         if (m_organism->GetPhenotype().GetMatingType() == MATING_TYPE_FEMALE) mating_type = 0;
10383         else if (m_organism->GetPhenotype().GetMatingType() == MATING_TYPE_MALE) mating_type = 1;
10384         else mating_type = 2;
10385       }
10386       double immigrant_odds = m_organism->GetOrgInterface().CalcGroupOddsImmigrants(group_id, mating_type);
10387       double offspring_own_odds = m_organism->GetOrgInterface().CalcGroupOddsOffspring(m_organism);
10388       double offspring_others_odds = m_organism->GetOrgInterface().CalcGroupOddsOffspring(group_id);
10389 
10390       // Convert all odds to percent
10391       double percent_immigrants = immigrant_odds * 100 + 0.5;
10392       double percent_offspring_own = offspring_own_odds * 100 + 0.5;
10393       double percent_offspring_others = offspring_others_odds * 100 + 0.5;
10394 
10395       // Truncate percent to integer and place in registers
10396       GetRegister(REG_AX) = (int) percent_immigrants;
10397       GetRegister(REG_BX) = (int) percent_offspring_own;
10398       GetRegister(REG_CX) = (int) percent_offspring_others;
10399       exec_success = true;
10400     }
10401   }
10402   return exec_success;
10403 }
10404 
10405 /*! Create a link to the currently-faced cell.
10406  */
Inst_CreateLinkByFacing(cAvidaContext & ctx)10407 bool cHardwareCPU::Inst_CreateLinkByFacing(cAvidaContext& ctx)
10408 {
10409   const int wreg = FindModifiedRegister(REG_BX);
10410   m_organism->GetOrgInterface().CreateLinkByFacing(GetRegister(wreg));
10411   return true;
10412 }
10413 
10414 /*! Create a link to the cell specified by xy-coordinates.
10415  */
Inst_CreateLinkByXY(cAvidaContext & ctx)10416 bool cHardwareCPU::Inst_CreateLinkByXY(cAvidaContext& ctx)
10417 {
10418   const int xreg = FindModifiedRegister(REG_BX);
10419   const int yreg = FindNextRegister(xreg);
10420   const int wreg = FindNextRegister(yreg);
10421   m_organism->GetOrgInterface().CreateLinkByXY(GetRegister(xreg), GetRegister(yreg), GetRegister(wreg));
10422 
10423   return true;
10424 }
10425 
10426 /*! Create a link to the cell specified by index.
10427  */
Inst_CreateLinkByIndex(cAvidaContext & ctx)10428 bool cHardwareCPU::Inst_CreateLinkByIndex(cAvidaContext& ctx)
10429 {
10430   const int idxreg = FindModifiedRegister(REG_BX);
10431   const int wreg = FindNextRegister(idxreg);
10432   m_organism->GetOrgInterface().CreateLinkByIndex(GetRegister(idxreg), GetRegister(wreg));
10433   return true;
10434 }
10435 
10436 /*! Broadcast a message in the communication network.
10437 
10438  Messages sent by this instruction are only sent to organisms that they are connected to
10439  via a cDemeNetwork.
10440 
10441  NOTE: These messages are still retrieved in the normal way!
10442  */
Inst_NetworkBroadcast1(cAvidaContext & ctx)10443 bool cHardwareCPU::Inst_NetworkBroadcast1(cAvidaContext& ctx)
10444 {
10445   const int label_reg = FindModifiedRegister(REG_BX);
10446   const int data_reg = FindNextRegister(label_reg);
10447 
10448   cOrgMessage msg = cOrgMessage(m_organism);
10449   msg.SetLabel(GetRegister(label_reg));
10450   msg.SetData(GetRegister(data_reg));
10451   return m_organism->GetOrgInterface().NetworkBroadcast(msg);
10452 }
10453 
10454 /*! Unicast a message in the communication network.
10455  */
Inst_NetworkUnicast(cAvidaContext & ctx)10456 bool cHardwareCPU::Inst_NetworkUnicast(cAvidaContext& ctx)
10457 {
10458   const int label_reg = FindModifiedRegister(REG_BX);
10459   const int data_reg = FindNextRegister(label_reg);
10460 
10461   cOrgMessage msg = cOrgMessage(m_organism);
10462   msg.SetLabel(GetRegister(label_reg));
10463   msg.SetData(GetRegister(data_reg));
10464   return m_organism->GetOrgInterface().NetworkUnicast(msg);
10465 }
10466 
10467 /*! Rotate the current active link by the contents of register ?BX?.
10468  */
Inst_NetworkRotate(cAvidaContext & ctx)10469 bool cHardwareCPU::Inst_NetworkRotate(cAvidaContext& ctx)
10470 {
10471   const int reg = FindModifiedRegister(REG_BX);
10472   return m_organism->GetOrgInterface().NetworkRotate(GetRegister(reg));
10473 }
10474 
10475 /*! Select the current active link from the contents of register ?BX?.
10476  */
Inst_NetworkSelect(cAvidaContext & ctx)10477 bool cHardwareCPU::Inst_NetworkSelect(cAvidaContext& ctx)
10478 {
10479   const int reg = FindModifiedRegister(REG_BX);
10480   return m_organism->GetOrgInterface().NetworkSelect(GetRegister(reg));
10481 }
10482 
10483 
Inst_GetTimeUsed(cAvidaContext & ctx)10484 bool cHardwareCPU::Inst_GetTimeUsed(cAvidaContext& ctx)
10485 {
10486   GetRegister(FindModifiedRegister(REG_BX)) = m_organism->GetPhenotype().GetTimeUsed();
10487   return true;
10488 }
10489 
Inst_DonateResToDeme(cAvidaContext & ctx)10490 bool  cHardwareCPU::Inst_DonateResToDeme(cAvidaContext& ctx)
10491 {
10492   m_organism->DonateResConsumedToDeme();
10493   return true;
10494 }
10495 
IncrementTaskSwitchingCost(int cost)10496 void cHardwareCPU::IncrementTaskSwitchingCost(int cost)
10497 {
10498   m_task_switching_cost += cost;
10499 }
10500 
10501 
Inst_ApplyPointMutations(cAvidaContext & ctx)10502 bool cHardwareCPU::Inst_ApplyPointMutations(cAvidaContext& ctx)
10503 {
10504   // If repairs are off...
10505   if(m_world->GetConfig().POINT_MUT_REPAIR_START.Get() == 0) {
10506     double point_mut_prob = m_world->GetConfig().INST_POINT_MUT_PROB.Get();
10507     int num_mut = m_organism->GetHardware().PointMutate(ctx, point_mut_prob);
10508     m_organism->IncPointMutations(num_mut);
10509   } else {
10510     // incur cost of repairs.
10511     int cost = m_world->GetConfig().INST_POINT_REPAIR_COST.Get();
10512     m_task_switching_cost += cost;
10513   }
10514   return true;
10515 }
10516 
Inst_ApplyVaryingPointMutations(cAvidaContext & ctx)10517 bool cHardwareCPU::Inst_ApplyVaryingPointMutations(cAvidaContext& ctx)
10518 {
10519   int last_task = m_organism->GetPhenotype().GetLastTaskID();
10520   // Check that the org performed a task...
10521   if (last_task != -1) {
10522     // Point mut prob is mutation rate * slope * task last performed
10523     double point_mut_prob = m_world->GetConfig().INST_POINT_MUT_PROB.Get() * m_world->GetConfig().INST_POINT_MUT_SLOPE.Get() * last_task;
10524     int num_mut = m_organism->GetHardware().PointMutate(ctx, point_mut_prob);
10525     m_organism->IncPointMutations(num_mut);
10526   }
10527   return true;
10528 }
10529 
Inst_ApplyPointMutationsGroupRandom(cAvidaContext & ctx)10530 bool cHardwareCPU::Inst_ApplyPointMutationsGroupRandom(cAvidaContext& ctx)
10531 {
10532   double point_mut_prob = m_world->GetConfig().INST_POINT_MUT_PROB.Get();
10533 
10534   // Check for test CPU
10535   if (m_organism->GetOrgInterface().GetDeme() == NULL) return false;
10536 
10537   // Grab a random member of the deme.
10538   // Pick a random starting location...
10539 
10540   int deme_size = m_organism->GetDeme()->GetSize();
10541   int start_pos = ctx.GetRandom().GetInt(0,deme_size);
10542 
10543   for (int i=0; i<deme_size; ++i) {
10544     int pos = (i + start_pos) % deme_size;
10545     cPopulationCell& cell = m_organism->GetDeme()->GetCell(pos);
10546     if (cell.IsOccupied()) {
10547       cOrganism* sl = cell.GetOrganism();
10548       int num_mut = sl->GetHardware().PointMutate(ctx, point_mut_prob);
10549       sl->IncPointMutations(num_mut);
10550       return true;
10551     }
10552   }
10553   return true;
10554 }
10555 
Inst_ApplyPointMutationsGroupGS(cAvidaContext & ctx)10556 bool cHardwareCPU::Inst_ApplyPointMutationsGroupGS(cAvidaContext& ctx)
10557 {
10558   double point_mut_prob = m_world->GetConfig().INST_POINT_MUT_PROB.Get();
10559 
10560   // Check for test CPU
10561   if (m_organism->GetOrgInterface().GetDeme() == NULL) return false;
10562 
10563   // Grab a random member of the deme.
10564   // Pick a random starting location...
10565   int deme_size = m_organism->GetDeme()->GetSize();
10566   int start_pos = ctx.GetRandom().GetInt(0,deme_size);
10567   bool gs = m_organism->IsGermline();
10568 
10569   for (int i=0; i<deme_size; ++i) {
10570     int pos = (i + start_pos) % deme_size;
10571     cPopulationCell& cell = m_organism->GetDeme()->GetCell(pos);
10572     if (cell.IsOccupied()) {
10573       cOrganism* sl = cell.GetOrganism();
10574       if (gs == sl->IsGermline()) {
10575         int num_mut = sl->GetHardware().PointMutate(ctx, point_mut_prob);
10576         sl->IncPointMutations(num_mut);
10577         return true;
10578       }
10579     }
10580   }
10581   return true;
10582 }
10583 
10584 
Inst_JoinGermline(cAvidaContext & ctx)10585 bool cHardwareCPU::Inst_JoinGermline(cAvidaContext& ctx) {
10586   m_organism->JoinGermline();
10587   return true;
10588 }
10589 
Inst_ExitGermline(cAvidaContext & ctx)10590 bool cHardwareCPU::Inst_ExitGermline(cAvidaContext& ctx) {
10591   m_organism->ExitGermline();
10592   return true;
10593 }
10594 
Inst_RepairPointMutOn(cAvidaContext & ctx)10595 bool cHardwareCPU::Inst_RepairPointMutOn(cAvidaContext& ctx){
10596   m_organism->RepairPointMutOn();
10597   return true;
10598 }
10599 
Inst_RepairPointMutOff(cAvidaContext & ctx)10600 bool cHardwareCPU::Inst_RepairPointMutOff(cAvidaContext& ctx){
10601   m_organism->RepairPointMutOff();
10602   return true;
10603 }
10604 
10605 /***
10606     Mating type instructions
10607 ***/
10608 
Inst_SetMatingTypeMale(cAvidaContext & ctx)10609 bool  cHardwareCPU::Inst_SetMatingTypeMale(cAvidaContext& ctx)
10610 {
10611   //Check if the organism has already set its sex to female
10612   if (m_organism->GetPhenotype().GetMatingType() == MATING_TYPE_FEMALE) {
10613     //If so, fail
10614     return false;
10615   } else {
10616     //Otherwise, set the current sex to male
10617     if (m_organism->GetOrgInterface().HasOpinion(m_organism)) {
10618       // since org can't be female by this point, only need to figure out if male (type 1) or juv (type 2)
10619       int old_type = 1;
10620       if (m_organism->GetPhenotype().GetMatingType() == MATING_TYPE_JUVENILE) old_type = 2;
10621       m_organism->GetOrgInterface().ChangeGroupMatingTypes(m_organism, m_organism->GetOpinion().first, old_type, 1);
10622     }
10623     m_organism->GetPhenotype().SetMatingType(MATING_TYPE_MALE);
10624   }
10625   return true;
10626 }
10627 
Inst_SetMatingTypeFemale(cAvidaContext & ctx)10628 bool  cHardwareCPU::Inst_SetMatingTypeFemale(cAvidaContext& ctx)
10629 {
10630   //Check if the organism has already set its sex to male
10631   if (m_organism->GetPhenotype().GetMatingType() == MATING_TYPE_MALE) {
10632     //If so, fail
10633     return false;
10634   } else {
10635     //Otherwise, set the current sex to female
10636     if (m_organism->GetOrgInterface().HasOpinion(m_organism)) {
10637       // since org can't be male by this point, only need to figure out if female (type 0) or juv (type 2)
10638       int old_type = 0;
10639       if (m_organism->GetPhenotype().GetMatingType() == MATING_TYPE_JUVENILE) old_type = 2;
10640       m_organism->GetOrgInterface().ChangeGroupMatingTypes(m_organism, m_organism->GetOpinion().first, old_type, 0);
10641     }
10642     m_organism->GetPhenotype().SetMatingType(MATING_TYPE_FEMALE);
10643   }
10644   return true;
10645 }
10646 
Inst_SetMatingTypeJuvenile(cAvidaContext & ctx)10647 bool  cHardwareCPU::Inst_SetMatingTypeJuvenile(cAvidaContext& ctx)
10648 {
10649   //Set the organism's sex to juvenile
10650   //In this way, an organism that has already matured as male or female can change its sex
10651   // if this instruction is included in the instruction set
10652   if (m_organism->GetOrgInterface().HasOpinion(m_organism)) {
10653     int old_type = 0;
10654     if (m_organism->GetPhenotype().GetMatingType() == MATING_TYPE_MALE) old_type = 1;
10655     else if (m_organism->GetPhenotype().GetMatingType() == MATING_TYPE_JUVENILE) old_type = 2;
10656     m_organism->GetOrgInterface().ChangeGroupMatingTypes(m_organism, m_organism->GetOpinion().first, old_type, 2);
10657   }
10658   m_organism->GetPhenotype().SetMatingType(MATING_TYPE_JUVENILE);
10659   return true;
10660 }
10661 
Inst_DivideSexMatingType(cAvidaContext & ctx)10662 bool cHardwareCPU::Inst_DivideSexMatingType(cAvidaContext& ctx)
10663 {
10664   //Check if the organism is sexually mature
10665   if (m_organism->GetPhenotype().GetMatingType() == MATING_TYPE_JUVENILE) {
10666     //If not, fail
10667     return false;
10668   } else {
10669     //Otherwise, divide
10670     return Inst_HeadDivideSex(ctx);
10671   }
10672 }
10673 
Inst_IfMatingTypeMale(cAvidaContext & ctx)10674 bool cHardwareCPU::Inst_IfMatingTypeMale(cAvidaContext& ctx)
10675 {
10676   //Execute the next instruction if the organism's mating type is male
10677   if (m_organism->GetPhenotype().GetMatingType() != MATING_TYPE_MALE)  getIP().Advance();
10678   return true;
10679 }
10680 
Inst_IfMatingTypeFemale(cAvidaContext & ctx)10681 bool cHardwareCPU::Inst_IfMatingTypeFemale(cAvidaContext& ctx)
10682 {
10683   //Execute the next instruction if the organism's mating type is female
10684   if (m_organism->GetPhenotype().GetMatingType() != MATING_TYPE_FEMALE)  getIP().Advance();
10685   return true;
10686 }
10687 
Inst_IfMatingTypeJuvenile(cAvidaContext & ctx)10688 bool cHardwareCPU::Inst_IfMatingTypeJuvenile(cAvidaContext& ctx)
10689 {
10690   //Execute the next instruction if the organism has not matured sexually
10691   if (m_organism->GetPhenotype().GetMatingType() != MATING_TYPE_JUVENILE)  getIP().Advance();
10692   return true;
10693 }
10694 
Inst_IncrementMatingDisplayA(cAvidaContext & ctx)10695 bool cHardwareCPU::Inst_IncrementMatingDisplayA(cAvidaContext& ctx)
10696 {
10697   //Increment the organism's mating display A trait
10698   int counter = m_organism->GetPhenotype().GetCurMatingDisplayA();
10699   counter++;
10700   m_organism->GetPhenotype().SetCurMatingDisplayA(counter);
10701   return true;
10702 }
10703 
Inst_IncrementMatingDisplayB(cAvidaContext & ctx)10704 bool cHardwareCPU::Inst_IncrementMatingDisplayB(cAvidaContext& ctx)
10705 {
10706   //Increment the organism's mating display A trait
10707   int counter = m_organism->GetPhenotype().GetCurMatingDisplayB();
10708   counter++;
10709   m_organism->GetPhenotype().SetCurMatingDisplayB(counter);
10710   return true;
10711 }
10712 
Inst_SetMatingDisplayA(cAvidaContext & ctx)10713 bool cHardwareCPU::Inst_SetMatingDisplayA(cAvidaContext& ctx)
10714 //Sets the display value a to be equal to the value of ?BX?
10715 {
10716   //Get the register and its contents as the new display value
10717   const int reg_used = FindModifiedRegister(REG_BX);
10718   const int new_display = GetRegister(reg_used);
10719 
10720   //Set the organism's mating display A trait
10721   m_organism->GetPhenotype().SetCurMatingDisplayA(new_display);
10722   return true;
10723 }
10724 
Inst_SetMatingDisplayB(cAvidaContext & ctx)10725 bool cHardwareCPU::Inst_SetMatingDisplayB(cAvidaContext& ctx)
10726 //Sets the display value b to be equal to the value of ?BX?
10727 {
10728   //Get the register and its contents as the new display value
10729   const int reg_used = FindModifiedRegister(REG_BX);
10730   const int new_display = GetRegister(reg_used);
10731 
10732   //Set the organism's mating display A trait
10733   m_organism->GetPhenotype().SetCurMatingDisplayB(new_display);
10734   return true;
10735 }
10736 
Inst_SetMatePreference(cAvidaContext & ctx,int mate_pref)10737 bool cHardwareCPU::Inst_SetMatePreference(cAvidaContext& ctx, int mate_pref)
10738 {
10739   m_organism->GetPhenotype().SetMatePreference(mate_pref);
10740   return true;
10741 }
Inst_SetMatePreferenceHighestDisplayA(cAvidaContext & ctx)10742 bool cHardwareCPU::Inst_SetMatePreferenceHighestDisplayA(cAvidaContext& ctx) { return Inst_SetMatePreference(ctx, MATE_PREFERENCE_HIGHEST_DISPLAY_A); }
Inst_SetMatePreferenceHighestDisplayB(cAvidaContext & ctx)10743 bool cHardwareCPU::Inst_SetMatePreferenceHighestDisplayB(cAvidaContext& ctx) { return Inst_SetMatePreference(ctx, MATE_PREFERENCE_HIGHEST_DISPLAY_B); }
Inst_SetMatePreferenceRandom(cAvidaContext & ctx)10744 bool cHardwareCPU::Inst_SetMatePreferenceRandom(cAvidaContext& ctx) { return Inst_SetMatePreference(ctx, MATE_PREFERENCE_RANDOM); }
Inst_SetMatePreferenceHighestMerit(cAvidaContext & ctx)10745 bool cHardwareCPU::Inst_SetMatePreferenceHighestMerit(cAvidaContext& ctx) { return Inst_SetMatePreference(ctx, MATE_PREFERENCE_HIGHEST_MERIT); }
10746