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