/* Core Wars. * Copyright (C) 1999 Walter Hofmann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include "main.h" #include "main-gui.h" #include "program.h" #include "program-cw.h" #include "execute.h" #include "execute-cw.h" #include "statistic.h" #include "pstatistic.h" #include "options.h" #include "tournament.h" #define FOLD(x) ((x)thread) { remove = FALSE; t = p->thread; p->thread = t->next; pc = t->pc; mark_inactive (pc); IR = memory[pc].content.command; switch (IR.command & RC_AM_A_MASK) { case RC_AM_A_IMMEDIATE: PA = 0; IRA = memory[pc].content.command; break; case RC_AM_A_DIRECT: PA = IR.a.number; IRA = memory[FOLD(pc+PA)].content.command; break; case RC_AM_A_PRE_DEC_A: PA = IR.a.number; if (!memory[FOLD(pc+PA)].content.command.a.number--) memory[FOLD(pc+PA)].content.command.a.number = SIZE-1; MEMORY_CHANGE_OWNER_INDEX (FOLD(pc+PA), p); mark (FOLD(pc+PA), FALSE); PA = FOLD(memory[FOLD(pc+PA)].content.command.a.number+PA); IRA = memory[FOLD(pc+PA)].content.command; break; case RC_AM_A_PRE_DEC_B: PA = IR.a.number; if (!memory[FOLD(pc+PA)].content.command.b.number--) memory[FOLD(pc+PA)].content.command.b.number = SIZE-1; MEMORY_CHANGE_OWNER_INDEX (FOLD(pc+PA), p); mark (FOLD(pc+PA), FALSE); PA = FOLD(memory[FOLD(pc+PA)].content.command.b.number+PA); IRA = memory[FOLD(pc+PA)].content.command; break; case RC_AM_A_POST_INC_A: PA = IR.a.number; PIP = FOLD(pc+PA); PA = FOLD(memory[FOLD(pc+PA)].content.command.a.number+PA); IRA = memory[FOLD(pc+PA)].content.command; if (++memory[PIP].content.command.a.number==SIZE) memory[PIP].content.command.a.number = 0; MEMORY_CHANGE_OWNER_INDEX (PIP, p); mark (PIP, FALSE); break; case RC_AM_A_POST_INC_B: PA = IR.a.number; PIP = FOLD(pc+PA); PA = FOLD(memory[FOLD(pc+PA)].content.command.b.number+PA); IRA = memory[FOLD(pc+PA)].content.command; if (++memory[PIP].content.command.b.number==SIZE) memory[PIP].content.command.b.number = 0; MEMORY_CHANGE_OWNER_INDEX (PIP, p); mark (PIP, FALSE); break; case RC_AM_A_INDIRECT_A: PA = IR.a.number; PA = FOLD(memory[FOLD(pc+PA)].content.command.a.number+PA); IRA = memory[FOLD(pc+PA)].content.command; break; case RC_AM_A_INDIRECT_B: PA = IR.a.number; PA = FOLD(memory[FOLD(pc+PA)].content.command.b.number+PA); IRA = memory[FOLD(pc+PA)].content.command; break; } switch (IR.command & RC_AM_B_MASK) { case RC_AM_B_IMMEDIATE: PB = 0; IRB = memory[pc].content.command; break; case RC_AM_B_DIRECT: PB = IR.b.number; IRB = memory[FOLD(pc+PB)].content.command; break; case RC_AM_B_PRE_DEC_A: PB = IR.b.number; if (!memory[FOLD(pc+PB)].content.command.a.number--) memory[FOLD(pc+PB)].content.command.a.number = SIZE-1; MEMORY_CHANGE_OWNER_INDEX (FOLD(pc+PB), p); mark (FOLD(pc+PB), FALSE); PB = FOLD(memory[FOLD(pc+PB)].content.command.a.number+PB); IRB = memory[FOLD(pc+PB)].content.command; break; case RC_AM_B_PRE_DEC_B: PB = IR.b.number; if (!memory[FOLD(pc+PB)].content.command.b.number--) memory[FOLD(pc+PB)].content.command.b.number = SIZE-1; MEMORY_CHANGE_OWNER_INDEX (FOLD(pc+PB), p); mark (FOLD(pc+PB), FALSE); PB = FOLD(memory[FOLD(pc+PB)].content.command.b.number+PB); IRB = memory[FOLD(pc+PB)].content.command; break; case RC_AM_B_POST_INC_A: PB = IR.b.number; PIP = FOLD(pc+PB); PB = FOLD(memory[FOLD(pc+PB)].content.command.a.number+PB); IRB = memory[FOLD(pc+PB)].content.command; if (++memory[PIP].content.command.a.number==SIZE) memory[PIP].content.command.a.number = 0; MEMORY_CHANGE_OWNER_INDEX (PIP, p); mark (PIP, FALSE); break; case RC_AM_B_POST_INC_B: PB = IR.b.number; PIP = FOLD(pc+PB); PB = FOLD(memory[FOLD(pc+PB)].content.command.b.number+PB); IRB = memory[FOLD(pc+PB)].content.command; if (++memory[PIP].content.command.b.number==SIZE) memory[PIP].content.command.b.number = 0; MEMORY_CHANGE_OWNER_INDEX (PIP, p); mark (PIP, FALSE); break; case RC_AM_B_INDIRECT_A: PB = IR.b.number; PB = FOLD(memory[FOLD(pc+PB)].content.command.a.number+PB); IRB = memory[FOLD(pc+PB)].content.command; break; case RC_AM_B_INDIRECT_B: PB = IR.b.number; PB = FOLD(memory[FOLD(pc+PB)].content.command.b.number+PB); IRB = memory[FOLD(pc+PB)].content.command; break; } switch (IR.command & RC_CMD_MASK) { case RC_CMD_DAT: remove = TRUE; break; case RC_CMD_MOV: switch (IR.command & RC_MOD_MASK) { case RC_MOD_A: memory[FOLD(pc+PB)].content.command.a.number = IRA.a.number; break; case RC_MOD_B: memory[FOLD(pc+PB)].content.command.b.number = IRA.b.number; break; case RC_MOD_AB: memory[FOLD(pc+PB)].content.command.b.number = IRA.a.number; break; case RC_MOD_BA: memory[FOLD(pc+PB)].content.command.a.number = IRA.b.number; break; case RC_MOD_F: memory[FOLD(pc+PB)].content.command.a.number = IRA.a.number; memory[FOLD(pc+PB)].content.command.b.number = IRA.b.number; break; case RC_MOD_X: memory[FOLD(pc+PB)].content.command.b.number = IRA.a.number; memory[FOLD(pc+PB)].content.command.a.number = IRA.b.number; break; case RC_MOD_I: memory[FOLD(pc+PB)].content.command = IRA; memory[FOLD(pc+PB)].contains_code = (memory[FOLD(pc+PB)].content.command.command & RC_CMD_MASK)!=RC_CMD_DAT; break; } MEMORY_CHANGE_OWNER_INDEX (FOLD(pc+PB), p); mark (FOLD(pc+PB), FALSE); break; #define ARITH(op)\ do switch (IR.command & RC_MOD_MASK)\ {\ case RC_MOD_A:\ memory[FOLD(pc+PB)].content.command.a.number = (IRB.a.number op IRA.a.number+SIZE) % SIZE;\ break;\ case RC_MOD_B:\ memory[FOLD(pc+PB)].content.command.b.number = (IRB.b.number op IRA.b.number+SIZE) % SIZE;\ break;\ case RC_MOD_AB:\ memory[FOLD(pc+PB)].content.command.b.number = (IRB.b.number op IRA.a.number+SIZE) % SIZE;\ break;\ case RC_MOD_BA:\ memory[FOLD(pc+PB)].content.command.a.number = (IRB.a.number op IRA.b.number+SIZE) % SIZE;\ break;\ case RC_MOD_F:\ case RC_MOD_I:\ memory[FOLD(pc+PB)].content.command.a.number = (IRB.a.number op IRA.a.number+SIZE) % SIZE;\ memory[FOLD(pc+PB)].content.command.b.number = (IRB.b.number op IRA.b.number+SIZE) % SIZE;\ break;\ case RC_MOD_X:\ memory[FOLD(pc+PB)].content.command.b.number = (IRB.b.number op IRA.a.number+SIZE) % SIZE;\ memory[FOLD(pc+PB)].content.command.a.number = (IRB.a.number op IRA.b.number+SIZE) % SIZE;\ break;\ } while (0) #define ARITH_DIV(op)\ do switch (IR.command & RC_MOD_MASK)\ {\ case RC_MOD_A:\ if (IRA.a.number)\ memory[FOLD(pc+PB)].content.command.a.number = (IRB.a.number op IRA.a.number+SIZE) % SIZE;\ break;\ case RC_MOD_B:\ if (IRA.b.number)\ memory[FOLD(pc+PB)].content.command.b.number = (IRB.b.number op IRA.b.number+SIZE) % SIZE;\ break;\ case RC_MOD_AB:\ if (IRA.a.number)\ memory[FOLD(pc+PB)].content.command.b.number = (IRB.b.number op IRA.a.number+SIZE) % SIZE;\ break;\ case RC_MOD_BA:\ if (IRA.b.number)\ memory[FOLD(pc+PB)].content.command.a.number = (IRB.a.number op IRA.b.number+SIZE) % SIZE;\ break;\ case RC_MOD_F:\ case RC_MOD_I:\ if (IRA.a.number)\ memory[FOLD(pc+PB)].content.command.a.number = (IRB.a.number op IRA.a.number+SIZE) % SIZE;\ if (IRA.b.number)\ memory[FOLD(pc+PB)].content.command.b.number = (IRB.b.number op IRA.b.number+SIZE) % SIZE;\ break;\ case RC_MOD_X:\ if (IRA.a.number)\ memory[FOLD(pc+PB)].content.command.b.number = (IRB.b.number op IRA.a.number+SIZE) % SIZE;\ if (IRA.b.number)\ memory[FOLD(pc+PB)].content.command.a.number = (IRB.a.number op IRA.b.number+SIZE) % SIZE;\ break;\ } while (0) #define ARITH_FOLD(op,of)\ do switch (IR.command & RC_MOD_MASK)\ {\ case RC_MOD_A:\ memory[FOLD(pc+PB)].content.command.a.number = FOLD(IRB.a.number op IRA.a.number+of);\ break;\ case RC_MOD_B:\ memory[FOLD(pc+PB)].content.command.b.number = FOLD(IRB.b.number op IRA.b.number+of);\ break;\ case RC_MOD_AB:\ memory[FOLD(pc+PB)].content.command.b.number = FOLD(IRB.b.number op IRA.a.number+of);\ break;\ case RC_MOD_BA:\ memory[FOLD(pc+PB)].content.command.a.number = FOLD(IRB.a.number op IRA.b.number+of);\ break;\ case RC_MOD_F:\ case RC_MOD_I:\ memory[FOLD(pc+PB)].content.command.a.number = FOLD(IRB.a.number op IRA.a.number+of);\ memory[FOLD(pc+PB)].content.command.b.number = FOLD(IRB.b.number op IRA.b.number+of);\ break;\ case RC_MOD_X:\ memory[FOLD(pc+PB)].content.command.b.number = FOLD(IRB.b.number op IRA.a.number+of);\ memory[FOLD(pc+PB)].content.command.a.number = FOLD(IRB.a.number op IRA.b.number+of);\ break;\ } while (0) #define ZEROCHECK\ do switch (IR.command & RC_MOD_MASK)\ {\ case RC_MOD_A:\ case RC_MOD_AB:\ if (!IRA.a.number)\ remove = TRUE;\ break;\ case RC_MOD_B:\ case RC_MOD_BA:\ if (!IRA.b.number)\ remove = TRUE;\ break;\ case RC_MOD_F:\ case RC_MOD_I:\ case RC_MOD_X:\ if (!IRA.a.number || !IRA.b.number)\ remove = TRUE;\ break;\ } while (0) case RC_CMD_ADD: ARITH_FOLD (+, 0); MEMORY_CHANGE_OWNER_INDEX (FOLD(pc+PB), p); mark (FOLD(pc+PB), FALSE); break; case RC_CMD_SUB: ARITH_FOLD (-, SIZE); MEMORY_CHANGE_OWNER_INDEX (FOLD(pc+PB), p); mark (FOLD(pc+PB), FALSE); break; case RC_CMD_MUL: ARITH (*); MEMORY_CHANGE_OWNER_INDEX (FOLD(pc+PB), p); mark (FOLD(pc+PB), FALSE); break; case RC_CMD_DIV: ARITH_DIV (/); ZEROCHECK; MEMORY_CHANGE_OWNER_INDEX (FOLD(pc+PB), p); mark (FOLD(pc+PB), FALSE); break; case RC_CMD_MOD: ARITH_DIV (%); ZEROCHECK; MEMORY_CHANGE_OWNER_INDEX (FOLD(pc+PB), p); mark (FOLD(pc+PB), FALSE); break; case RC_CMD_JMP: pc += PA-1; /* will FOLD later! */ break; case RC_CMD_JMZ: switch (IR.command & RC_MOD_MASK) { case RC_MOD_A: case RC_MOD_BA: if (IRB.a.number==0) pc += PA-1; /* will FOLD later! */ break; case RC_MOD_B: case RC_MOD_AB: if (IRB.b.number==0) pc += PA-1; /* will FOLD later! */ break; case RC_MOD_F: case RC_MOD_X: case RC_MOD_I: if (IRB.a.number==0 && IRB.b.number==0) pc += PA-1; /* will FOLD later! */ break; } break; case RC_CMD_JMN: switch (IR.command & RC_MOD_MASK) { case RC_MOD_A: case RC_MOD_BA: if (IRB.a.number!=0) pc += PA-1; /* will FOLD later! */ break; case RC_MOD_B: case RC_MOD_AB: if (IRB.b.number!=0) pc += PA-1; /* will FOLD later! */ break; case RC_MOD_F: case RC_MOD_X: case RC_MOD_I: if (IRB.a.number!=0 || IRB.b.number!=0) pc += PA-1; /* will FOLD later! */ break; } break; case RC_CMD_IJZ: MEMORY_CHANGE_OWNER_INDEX (FOLD(pc+PB), p); /* do this first as pc can change */ mark (FOLD(pc+PB), FALSE); switch (IR.command & RC_MOD_MASK) { case RC_MOD_A: case RC_MOD_BA: if (++memory[FOLD(pc+PB)].content.command.a.number==SIZE) memory[FOLD(pc+PB)].content.command.a.number = 0; if (IRB.a.number!=-1) pc += PA-1; /* will FOLD later! */ break; case RC_MOD_B: case RC_MOD_AB: if (++memory[FOLD(pc+PB)].content.command.b.number==SIZE) memory[FOLD(pc+PB)].content.command.b.number = 0; if (IRB.b.number!=-1) pc += PA-1; /* will FOLD later! */ break; case RC_MOD_F: case RC_MOD_X: case RC_MOD_I: if (++memory[FOLD(pc+PB)].content.command.a.number==SIZE) memory[FOLD(pc+PB)].content.command.a.number = 0; if (++memory[FOLD(pc+PB)].content.command.b.number==SIZE) memory[FOLD(pc+PB)].content.command.b.number = 0; if (IRB.a.number!=-1 || IRB.b.number!=-1) pc += PA-1; /* will FOLD later! */ break; } break; case RC_CMD_DJN: MEMORY_CHANGE_OWNER_INDEX (FOLD(pc+PB), p); /* do this first as pc can change */ mark (FOLD(pc+PB), FALSE); switch (IR.command & RC_MOD_MASK) { case RC_MOD_A: case RC_MOD_BA: if (!memory[FOLD(pc+PB)].content.command.a.number--) memory[FOLD(pc+PB)].content.command.a.number = SIZE-1; if (IRB.a.number!=1) pc += PA-1; /* will FOLD later! */ break; case RC_MOD_B: case RC_MOD_AB: if (!memory[FOLD(pc+PB)].content.command.b.number--) memory[FOLD(pc+PB)].content.command.b.number = SIZE-1; if (IRB.b.number!=1) pc += PA-1; /* will FOLD later! */ break; case RC_MOD_F: case RC_MOD_X: case RC_MOD_I: if (!memory[FOLD(pc+PB)].content.command.a.number--) memory[FOLD(pc+PB)].content.command.a.number = SIZE-1; if (!memory[FOLD(pc+PB)].content.command.b.number--) memory[FOLD(pc+PB)].content.command.b.number = SIZE-1; if (IRB.a.number!=1 || IRB.b.number!=1) pc += PA-1; /* will FOLD later! */ break; } break; case RC_CMD_SEQ: switch (IR.command & RC_MOD_MASK) { case RC_MOD_A: if (IRA.a.number==IRB.a.number) pc++; /* will FOLD later! */ break; case RC_MOD_B: if (IRA.b.number==IRB.b.number) pc++; /* will FOLD later! */ break; case RC_MOD_AB: if (IRA.a.number==IRB.b.number) pc++; /* will FOLD later! */ break; case RC_MOD_BA: if (IRA.b.number==IRB.a.number) pc++; /* will FOLD later! */ break; case RC_MOD_F: if (IRA.a.number==IRB.a.number && IRA.b.number==IRB.b.number) pc++; /* will FOLD later! */ break; case RC_MOD_X: if (IRA.a.number==IRB.b.number && IRA.b.number==IRB.a.number) pc++; /* will FOLD later! */ break; case RC_MOD_I: if (IRA.command==IRB.command && IRA.a.number==IRB.a.number && IRA.b.number==IRB.b.number) pc++; /* will FOLD later! */ break; } break; case RC_CMD_SNE: switch (IR.command & RC_MOD_MASK) { case RC_MOD_A: if (IRA.a.number!=IRB.a.number) pc++; /* will FOLD later! */ break; case RC_MOD_B: if (IRA.b.number!=IRB.b.number) pc++; /* will FOLD later! */ break; case RC_MOD_AB: if (IRA.a.number!=IRB.b.number) pc++; /* will FOLD later! */ break; case RC_MOD_BA: if (IRA.b.number!=IRB.a.number) pc++; /* will FOLD later! */ break; case RC_MOD_F: if (IRA.a.number!=IRB.a.number || IRA.b.number!=IRB.b.number) pc++; /* will FOLD later! */ break; case RC_MOD_X: if (IRA.a.number!=IRB.b.number || IRA.b.number!=IRB.a.number) pc++; /* will FOLD later! */ break; case RC_MOD_I: if (IRA.command!=IRB.command || IRA.a.number!=IRB.a.number || IRA.b.number!=IRB.b.number) pc++; /* will FOLD later! */ break; } break; case RC_CMD_SLT: switch (IR.command & RC_MOD_MASK) { case RC_MOD_A: if (IRA.a.numberthread_countnext = t->next; t2->prev = t; t->next = t2; t2->next->prev = t2; t2->pc = FOLD(pc+PA); p->thread_count++; thread_count++; mark_active (t2->pc, p); } break; case RC_CMD_NOP: break; } if (remove) { p->thread_count--; thread_count--; if (t==t->next) { if (memory[pc].owner && memory[pc].owner!=p) memory[pc].owner->kill_count++; free (t); p->thread = NULL; p->death_time = elapsed_time; process_alive--; } else { t->prev->next = t->next; t->next->prev = t->prev; free (t); /* We assume p->thread != t here. This can only be wrong after SPL, but then remove will be zero anyway.*/ } } else { pc = FOLD(pc+1); /* We MUST use FOLD here! */ mark_active (pc, p); t->pc = pc; } } } elapsed_time++; #ifndef CMD_LINE if (elapsed_time==MAX_CYCLES || !thread_count || (STOP_EARLY && process_alive==1 && process_count>1)) if (tournament_running) tournament_finished_game (); else execute_stop(); #endif } void rc_create_process_cmd (struct program *p, struct process *pr, int position) { int i,j; pr->program = p; pr->thread = malloc (sizeof (struct thread)); pr->thread->next = pr->thread; pr->thread->prev = pr->thread; pr->cell_count = 0; pr->kill_count = 0; i = position; pr->thread->pc = (i+p->lang.rc.org+SIZE) % SIZE; for (j=0; jlang.rc.size; j++, i = (i+1) % SIZE) { MEMORY_CHANGE_OWNER_INDEX (i, pr); memory[i].content.command.command = p->lang.rc.obj[j].command; memory[i].content.command.a.number = (p->lang.rc.obj[j].a.number % SIZE + SIZE) % SIZE; memory[i].content.command.b.number = (p->lang.rc.obj[j].b.number % SIZE + SIZE) % SIZE; memory[i].contains_code = (memory[i].content.command.command & RC_CMD_MASK)!=RC_CMD_DAT; mark (i, FALSE); } pr->thread_count = 1; pr->death_time = INT_MAX; mark_active (pr->thread->pc, pr); thread_count++; }