/* 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 CELL_MOVE_CODE_EQUAL(a,b) \ ((b)->command==CMD_MOVE && \ (a)->operand1->accessmode==(b)->operand1->accessmode && \ (a)->operand1->operand.value==(b)->operand1->operand.value && \ (a)->operand2->accessmode==(b)->operand2->accessmode && \ (a)->operand2->operand.value==(b)->operand2->operand.value) int is_valid (struct cw_operand *o, int i) { int j; switch (o->accessmode) { case AM_ADDRESS: case AM_CONSTANT: case AM_VALUE: return TRUE; case AM_INDIRECT: j = (o->operand.value+i+SIZE) % SIZE; if (memory[j].contains_code) return FALSE; return TRUE; } } inline int get_value (struct cw_operand *o, int i, int *value) { int j; switch (o->accessmode) { case AM_ADDRESS: *value = (o->operand.value+i+SIZE) % SIZE; return TRUE; case AM_CONSTANT: *value = o->operand.value; return TRUE; case AM_VALUE: j = (o->operand.value+i+SIZE) % SIZE; if (memory[j].contains_code) return FALSE; *value = memory[j].content.data; return TRUE; case AM_INDIRECT: j = (o->operand.value+i+SIZE) % SIZE; if (memory[j].contains_code) return FALSE; j = ((memory[j].content.data % SIZE)+SIZE) % SIZE; if (memory[j].contains_code) return FALSE; *value = memory[j].content.data; return TRUE; } } inline int get_reference (struct cw_operand *o, int i, struct cell **ref) { int j; switch (o->accessmode) { case AM_ADDRESS: return FALSE; case AM_CONSTANT: return FALSE; case AM_VALUE: j = (o->operand.value+i+SIZE) % SIZE; *ref = memory+j; return TRUE; case AM_INDIRECT: j = (o->operand.value+i+SIZE) % SIZE; if (memory[j].contains_code) return FALSE; j = ((memory[j].content.data % SIZE)+SIZE) % SIZE; *ref = memory+j; return TRUE; } } void cw_execute_step () { struct process *p; struct thread *t, *t2; int remove; struct cw_line *l; int value, value2; struct cell *dst, *ref, *ref2, *ref3; int i; for (i=0; ithread) { t = p->thread; p->thread = t->next; mark_inactive (t->pc); remove = TRUE; if (memory[t->pc].contains_code && !p->killing) { l = memory[t->pc].content.code; switch (l->command) { case CMD_MOVE: if (get_reference (l->operand2, t->pc, &dst)) if (get_value (l->operand1, t->pc, &value)) { dst->contains_code = FALSE; dst->content.data = value; MEMORY_CHANGE_OWNER_POINTER (dst, p); mark (dst-memory, FALSE); remove = FALSE; } else if (get_reference (l->operand1, t->pc, &ref)) { if (!ALLOW_SELF_MOVE && l->operand1->accessmode==AM_VALUE && l->operand2->accessmode==AM_VALUE && ref->contains_code && CELL_MOVE_CODE_EQUAL(l,ref->content.code)) break; MEMORY_CHANGE_OWNER_POINTER (dst, p); *dst = *ref; dst->owner = p; /* owner was overwritten by line above */ mark (dst-memory, FALSE); remove = FALSE; } break; case CMD_ADD: if (get_reference (l->operand2, t->pc, &dst)) if (!dst->contains_code) if (get_value (l->operand1, t->pc, &value)) { dst->content.data += value; MEMORY_CHANGE_OWNER_POINTER (dst, p); mark (dst-memory, FALSE); remove = FALSE; } break; case CMD_NEG: if (get_reference (l->operand2, t->pc, &dst)) if (get_value (l->operand1, t->pc, &value)) { dst->contains_code = FALSE; dst->content.data = -value; MEMORY_CHANGE_OWNER_POINTER (dst, p); mark (dst-memory, FALSE); remove = FALSE; } break; case CMD_MUL: if (get_reference (l->operand2, t->pc, &dst)) if (!dst->contains_code) if (get_value (l->operand1, t->pc, &value)) { dst->content.data *= value; MEMORY_CHANGE_OWNER_POINTER (dst, p); mark (dst-memory, FALSE); remove = FALSE; } break; case CMD_DIV: if (get_reference (l->operand2, t->pc, &dst)) if (!dst->contains_code) if (get_value (l->operand1, t->pc, &value)) if (value) { dst->content.data /= value; MEMORY_CHANGE_OWNER_POINTER (dst, p); mark (dst-memory, FALSE); remove = FALSE; } break; case CMD_MOD: if (get_reference (l->operand2, t->pc, &dst)) if (!dst->contains_code) if (get_value (l->operand1, t->pc, &value)) if (value) { dst->content.data %= value; MEMORY_CHANGE_OWNER_POINTER (dst, p); mark (dst-memory, FALSE); remove = FALSE; } break; case CMD_AND: if (get_reference (l->operand2, t->pc, &dst)) if (!dst->contains_code) if (get_value (l->operand1, t->pc, &value)) { dst->content.data &= value; MEMORY_CHANGE_OWNER_POINTER (dst, p); mark (dst-memory, FALSE); remove = FALSE; } break; case CMD_NOT: if (get_reference (l->operand2, t->pc, &dst)) if (get_value (l->operand1, t->pc, &value)) { dst->contains_code = FALSE; dst->content.data = !value; MEMORY_CHANGE_OWNER_POINTER (dst, p); mark (dst-memory, FALSE); remove = FALSE; } break; case CMD_EQUAL: if (is_valid (l->operand1, t->pc) && is_valid (l->operand2, t->pc)) { if (get_value (l->operand1, t->pc, &value) && get_value (l->operand2, t->pc, &value2) && value==value2) t->pc--; else if (get_reference (l->operand1, t->pc, &ref) && get_reference (l->operand2, t->pc, &ref2) && ref->contains_code==ref2->contains_code && ref->content.code==ref2->content.code) t->pc--; t->pc++; remove = FALSE; } break; case CMD_LESS: if (get_value (l->operand1, t->pc, &value) && get_value (l->operand2, t->pc, &value2)) { if (value>=value2) t->pc++; remove = FALSE; } break; case CMD_JUMP: if (get_reference (l->operand1, t->pc, &dst)) { t->pc = dst-memory-1; remove = FALSE; } break; case CMD_FORK: if (get_reference (l->operand1, t->pc, &dst)) if (p->thread_count>=MAX_THREADS) p->killing = TRUE; else { t2 = malloc (sizeof (struct thread)); t2->next = t; t2->prev = t->prev; t->prev = t2; t2->prev->next = t2; t2->pc = dst-memory; p->thread = t->next; p->thread_count++; thread_count++; remove = FALSE; } break; case CMD_INFO: if (get_value (l->operand1, t->pc, &value) && get_reference (l->operand2, t->pc, &ref)) { remove = FALSE; switch (value) { case 0: value = SIZE; break; case 1: value = DIMENSIONX; break; case 2: value = random() % SIZE; break; case 3: value = random() % DIMENSIONX; break; case 4: value = p->thread_count; break; case 5: value = elapsed_time; break; case 6: value = MAX_THREADS; break; default: remove = TRUE; } if (!remove) { ref->contains_code = FALSE; ref->content.data = value; MEMORY_CHANGE_OWNER_POINTER (ref, p); mark (ref-memory, FALSE); } } break; case CMD_OWN: if (get_reference (l->operand1, t->pc, &dst)) { if (dst->owner!=p) t->pc++; remove = FALSE; } break; case CMD_LOOP: if (get_reference (l->operand1, t->pc, &dst)) if (!dst->contains_code) if (get_reference (l->operand2, t->pc, &ref)) { dst->content.data--; MEMORY_CHANGE_OWNER_POINTER (dst, p); if (dst->content.data) t->pc = ref-memory-1; remove = FALSE; } break; case CMD_MOVEI: if (get_value (l->operand1, t->pc, &value)) if (get_value (l->operand2, t->pc, &value2)) if (get_reference (l->operand1, t->pc, &ref)) if (get_reference (l->operand2, t->pc, &ref2)) { MEMORY_CHANGE_OWNER_POINTER (ref, p); mark (ref-memory, FALSE); MEMORY_CHANGE_OWNER_POINTER (ref2, p); mark (ref2-memory, FALSE); ref3 = memory+(value % SIZE + SIZE) % SIZE; dst = memory+(value2 % SIZE + SIZE) % SIZE; MEMORY_CHANGE_OWNER_POINTER (dst, p); *dst = *ref3; dst->owner = p; /* owner was overwritten by line above */ mark (dst-memory, FALSE); ref->content.data++; ref2->content.data++; remove = FALSE; } break; } } if (remove) { p->thread_count--; thread_count--; if (t==t->next) { if (memory[t->pc].owner && memory[t->pc].owner!=p) memory[t->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); } } else { t->pc = (t->pc+1) % SIZE; mark_active (t->pc, p); } } } 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 cw_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; for (j=0; jlang.cw.opcode_number; j++, i = (i+1) % SIZE) { MEMORY_CHANGE_OWNER_INDEX (i, pr); if ((p->lang.cw.code[j])->command==CMD_DATA) { memory[i].contains_code = FALSE; if ((p->lang.cw.code[j])->operand1->accessmode==AM_CONSTANT) memory[i].content.data = (p->lang.cw.code[j])->operand1->operand.value; else memory[i].content.data = (p->lang.cw.code[j])->operand1->operand.value+i; } else { memory[i].contains_code = TRUE; memory[i].content.code = p->lang.cw.code[j]; } mark (i, FALSE); } i = (i-j+SIZE) % SIZE; while (!memory[i].contains_code && memory[i].owner==pr) i = (i+1) % SIZE; pr->thread->pc = i; pr->thread_count = 1; pr->death_time = INT_MAX; pr->killing = FALSE; mark_active (i, pr); thread_count++; }