[net.sources] corewars, yet another

ix269@sdccs6.UUCP (Jim) (07/29/84)

<>

Here is an updated version of corewars, I am working to
soon ingest the funhouse version into this so that everyone
can have everything, so to speak.

cut along the dotted line and extract with csh.

cheers--

	Jim

---------------------------------------------------------------------
echo Extracting Makefile
cat <<'poobahfig' > Makefile
#
#	Makefile for "Core Wars"  by  Berry Kercheval  (CopyRight 1984)
#
#		based on A.K. Dewdeney's Game May 1984 SciAm
#
#					( UNIX is a trademark of AT&T )

HDRS= cw.h global.h machdep.h      # std header, globals, Machine dependencies

CFILES= main.c load.c do.c misc.c

OBJS=   main.o load.o do.o misc.o

CFLAGS= -O -DUNIX_4_2

LFLAGS= -bchx -DUNIX_4_2

PRINT= lpr -Pexpress 	       	   # this weeks print command, and flags

corewars: $(HDRS) $(OBJS)
	@$(CC) $(CFLAGS) $(OBJS) -o corewars 

lint:
	lint $(LFLAGS) $(CFILES) > linterr

count:
	wc -l $(CFILES) $(HDRS)

print:
	$(PRINT) $(HDRS) $(CFILES) &

'poobahfig'
echo Extracting cw.h
cat <<'poobahfig' > cw.h
/*
 *	General defines for CoreWar, based on A.K. Dewdney's May 1984
 *	column in Scientific American.
 *
 *	Copyright 1984, Berry Kercheval.  All rights reserved.  Permission
 *	for distribution is granted provided no direct commercial
 *	advantage is gained, and that this copyright notice appears 
 *	on all copies.
 *
 *	many changes and amenditures by Jim of HCDE
 */

#define PROGRAM		"corewars"	/* the name of the program */

#define USAGE	"[-cdlot] <prog1> [<prog2>]"

/*	Game variables
 */

#define BUFSIZE		256	/* program line size */
#define COMCHAR		';'	/* comment character was a '/' */
#define	DISTANCE	1000	/* programs at least this far apart */
#define MAXPROGSIZE	1000	/* maximum number of executable lines */
#define	MEMSIZE		8000	/* the arena size */
#define TIMEOUT		120	/* playtime before 'DRAW', 120 cpu sec. */

/*	Convenience defines
 */

#define EVER		;;	/* for(EVER) */
#define FALSE			0	/* basic boolean value */
#define TRUE		1	/* basic boolean value */
#define TWENDASH	"--------------------"	/* 20 dashes */

#define iszero(m) 	(m.op == 0 && m.mode[A] == 0 && m.mode[B] == 0 \
				&& m.arg[A] == 0 && m.arg[B] == 0)
				/* determines if a memword is zeroed */

#define iswhite(c)	(c == ' ' || c == '\t' || c == ',')	
				/* white space, space which can be
				   ignored in parsing */
/*
 * The Redcode Op-code values
 */

#define		DAT	0    /* one operand, nonexecutable */
#define		MOV	1    /* move contents of SRC to DST, A ==> B */
#define		ADD	2    /* add contents of SRC to DST, A+B ==> B */
#define		SUB	3    /* subtract contents of SRC from DST, A-B ==> B */
#define		JMP	4    /* transfer control to DST, A ==> PC */
#define		JMZ	5    /* JMP A if contents of B == 0 */
#define		JMG	6    /* JMP A if contents of B > 0 */
#define		DJZ	7    /* decrement B, JMP A if B == 0 */
#define		CMP	8    /* if A != B skip next instruction */

#define		TOPOP	CMP	/* the highest value opcode */

/*
 * Operand addressing mode values
 */

#define DIRECT		0	/* ' ' */
#define IMMEDIATE	1	/* '#' */
#define INDIRECT	2	/* '@' */

/*	operand defines
 */

#define A	    0	/* operand and mode A are the first array elements */
#define B	    1	/* operand and mode B are the second array elements */
#define MAXOPERANDS 2	/* current limitation */

/*
 *	Redcode Instruction Format:
 *
 *	#    #     #   #### ####	<-- decimal digits
 *	OP ModeA ModeB AAAA BBBB
 *
 *	Max. instruction: 82,279,997,999 = 0x1 3245 222F
 *	Too bad it won't fit in an unsigned long (2,147,483,648)
 *
 *	TODO NOTE:  OP and Modes could be packed into an unsigned int
 */

struct memword{
    short op;			/* the opcode */
    short mode[MAXOPERANDS];	/* the addressing mode of operands */
    int   arg[MAXOPERANDS];	/* operands */
};

typedef struct memword memword;
typedef	long           address;	

extern int errno,		/* global error flag for perror */
	   error,		/* global loadtime syntax error flag */
	   dumpflag,		/* TRUE --> print post-mortem dump */
	   traceflag,		/* TRUE --> print execution trace */
           listflag,		/* TRUE --> print listing of loaded program */
	   draw(),		/* handle the timeout draw condition */
	   do_instruction(),	/* do an instruction of Redcode */

	   do_add(),		/* basic instructions */
	   do_cmp(),
	   do_mov(),
	   do_sub();   


extern char *op_str[],		/* string representations of opcodes */
	    mode_char[],	/* addressing mode characters */
	    *pr_inst();		/* returns formatted string rep. of a pointer */
				/* to a Redcode instruction suitable for %s */
extern address load(),		/* Redcode program loader */
	       do_jmp();	/* do JMP operation */

extern memword mem[MEMSIZE];	/* the simulated memory 'arena' */

extern void clear_mem(),	/* clear the game stack */
	    dump(),		/* do a memory dump on the game stack */
	    usage();		/* print usage message andd exit */

'poobahfig'
echo Extracting global.h
cat <<'poobahfig' > global.h
/*
 *	Globals for Core Wars a program for waring programs
 *
 *		copyrights in main body
 *
 *	Global values and initializations at beginning of main
 *	program.
 */

char *op_str[] =		/* strings for opcodes */
{
    "dat",	/* 0 */
    "mov",	/* 1 */
    "add",	/* 2 */
    "sub",	/* 3 */
    "jmp",	/* 4 */
    "jmz",	/* 5 */
    "jmg",	/* 6 */
    "djz",	/* 7 */
    "cmp",	/* 8 */
	0
};

char mode_char[] = { ' ', '#', '@', 0 }; /* addressing mode char's */
 
int     dumpflag   = FALSE,	/* TRUE --> print post-mortem dump */
	traceflag  = FALSE,	/* TRUE --> print execution trace */
        listflag   = FALSE,	/* TRUE --> print listing of loaded program */
	error	   = FALSE;	/* SYNTAX error during load */

char    *pr_inst();		/* returns formatted string rep. of a pointer
				   to a redcode instruction suitable for %s */

address load();			/* Redcode program loader */

memword mem[MEMSIZE];	/* the simulated memory 'arena' */

'poobahfig'
echo Extracting machdep.h
cat <<'poobahfig' > machdep.h
/*
 *	copyright stuff in main program
 *
 *	altered by:  Jim of HCDE
 *
 *	Unix is a trademark of AT&T
 */

#ifdef UNIX_4_2			    /* 4.2 Unix C library */
#  define RANDOM()	random()	/* a better version of rand() */
#  define SRANDOM(x)	srandom(x)	/* the seed function accompli */
   long random();
#else  				    /* 4.1 Unix C library */
#  define RANDOM()	rand()		/* use the lib or right your own */
#  define SRANDOM(x)	srand(x)	/* the seed function companion */
   int rand();
#endif					/* alter SHIFT def to suit */

'poobahfig'
echo Extracting main.c
cat <<'poobahfig' > main.c

/*
 *	"Core Wars"	version 2.0
 *
 *	Programs battle for supremacy in a simulated arena!  Based on A.K
 *	Dewdeney's May 1984 column in Scientific American.
 *
 *	Usage:
 *		corewars [-cdlot] [prog1] [prog2]
 *
 *			prog1 and prog2 must be ascii Redcode files.
 *
 *		    -c: Check mode, like a syntax checker. 
 *
 *		    -d: print post-mortem memory Dump.
 *
 *		    -l: print Listings while loading the Redcode programs.
 *
 *		    -o: inform corewars that you have only one program
 *
 *		    -t: print verbose execution Trace
 *
 *	This program assumes your C compiler supports structure assignment,
 *	as well as many other goodies.
 *
 *	Copyright 1984, Berry Kercheval.  All rights reserved.  Permission
 *	for distribution is granted provided no direct commercial
 *	advantage is gained, and that this copyright notice appears 
 *	on all copies.
 *
 *	Revision and maintenance by Jim of HCDE
 *
 */

#include <errno.h>	/* header file for perror */
#include <stdio.h>
#include <signal.h>	/* header for interrupt functions */
#include <sys/file.h>	/* header for access() and c. */
#include "cw.h"		/* program group header file */
#include "global.h"	/* main program header file for globals */
#include "machdep.h"	/* header file of machine or system dependencies */

main(argc, argv)
int   argc;
char  *argv[];
{
    register int  j;		/* utility index */

    register char *pv;		/* utility pointer */

    int  check,			/* check flag for debug mode */
	 winner,		/* who won? */
	 numfiles,		/* number of files to load */
	 tmp;			/* tmp variable */

    char *file[2];		/* the two ascii Redcode program files */

    register address pc_1,	/* addresses of program starting points. */
		     pc_2;	/* filled in by load() */

    check = FALSE;
    numfiles = 2;

    while ( --argc > 0 && (*++argv)[0] == '-')
	for (pv = argv[0] + 1; *pv != NULL ;pv++)
	    switch (*pv){
		case 'c':
		    check = TRUE;	/* check but do not execute */
		    continue;
		case 'd': 		/* print memory dump at end */
		    dumpflag = TRUE;
		    continue;
		case 'l': 		/* print listing at load-time */
		    listflag = TRUE;
		    continue;
		case 'o':		/* only one file */
		    check = TRUE;	/* suppress execution */
		    numfiles = 1;
		    continue;
		case 't': 		/* print execution trace */
		    traceflag = TRUE;
		    continue;
		default: 		/* flag not yet implimented */
		    fprintf(stderr, "Unknown flag '-%c'\n", *pv);
		    usage();
	    };
			/* last two arguments should 
			 * be names of two redcode files
			 */

    if (argc < numfiles)	/* usage file error, complain and exit */
	usage();

    if (argc > numfiles) {	/* perhaps to many heros to let user in */
	fprintf(stderr,"Error: extra unused command line arguments\n");
	usage();
    }
    
    SRANDOM(getpid());		/* set the seed for RANDOM() */

    if (numfiles == 2)
	tmp = (int)(RANDOM()&01);	/* random choice of first */
    else
	tmp = 0;

    for (j = 0; j < numfiles ;j++) {
	if (access(*argv, R_OK) != NULL) {	/* check read access */
	    perror(*argv);
	    exit(-1);
	}
	file[abs(j - tmp)] = *(argv++);		/* random first/second */
    }

    clear_mem();		/* Clear the arena! Clear the arena! */

    pc_1 = load(file[0]);		/* load up program 1 */

    if (numfiles == 2)
	pc_2 = load(file[1]);		/* load up program 2 */

    if (error) {			/* no execution if there was an error */
	printf("\n\nNot Executable, errors.\n");
	exit(1);
    }
    if (check) {
	printf("\n\nLooks good to me.\n");
	exit(0);
    }

    if (traceflag) {		/* print trace header here, after possible */
				/* load() listing */
	printf("\n\t%-33.20s%-20s\n", file[0], file[1]);
	printf("%s%s%s%s\n",TWENDASH,TWENDASH,TWENDASH,TWENDASH);
    }

    (void)signal(SIGALRM, draw);	/* set up for timeout, draw */
    (void)alarm(TIMEOUT);		/* give up after TIMEOUT seconds */

    winner = execute(pc_1, pc_2);	/* run the programs */

    (void)alarm(0);			/* turn off the alarm */

    if (winner == 1 || winner == 2) {/* allocate blame */
	printf("%s(%d) wins.\n", winner == 1 ? file[0] : file[1], winner);
    }
    else
	fprintf(stderr,"Error in execute -- bad value returned (%d)\n",winner);

    if (dumpflag)			/* post-mortem dump if requested */
	dump();

    exit(0);			/* Th-th-that's all folks */
}

'poobahfig'
echo Extracting load.c
cat <<'poobahfig' > load.c
/*
 *	load.c	load the programs into the stack
 */

#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include "cw.h"
#include "machdep.h"

/*
 *	load()	Load a Redcode file.  load the file at a random place
 *		in <mem>, not within <DISTANCE> of the other program.
 */

address
load(filename)
char *filename;
{
    register int  op,		/* op-code value */
		  i;		/* loop index */

    register char *ptr,		/* pointer within the line; used in parsing  */
	    	  *ip;		/* pointer within the line; used in parsing  */

    static address sp = 0;	/* stack pointer for last program */

    register address r;		/* where to load current instruction */

    char buf[BUFSIZE],		/* line buffer */
    	 *index();

    address start;		/* the returned start pc */

    FILE *f;			/* stream pointer to the input file */

    if (sp != 0L) {/* if not the first */
	r = sp + (address)(RANDOM() % (long)(abs((int)sp - MEMSIZE)));
				/* random spot in <mem> */
	while (abs((int)(r - sp)) < DISTANCE)
	    while(abs((int)(r - sp)) >= (MEMSIZE - MAXPROGSIZE))
		r = sp + (address)(RANDOM() % (long)(abs((int)sp - MEMSIZE)));
    }
    else    r = 0;

    sp = r;			/* point to load start for this program */
    start = 0;

    printf("\nloading %s at %d\n\n", filename, r);

 /* now load the file
 */

    f = fopen(filename, "r");
    if (f == NULL) {
	perror(filename);
	exit(-1);
    }

 /* 
  * There now follows a moderately crufty ad-hoc redcode assembler.
  * It's not modular or very structured, but it seems to work, and
  * redcode was so simple I didn't want to use YACC or LEX or SSL
  */

    while ( fgets(buf, BUFSIZE, f) != NULL ) {/* for each line in the file */

	if (r > MEMSIZE)	/* scroll around */
	    r %= MEMSIZE;
    				
	if ((ptr = index(buf, COMCHAR)) != NULL)/* zap comment */
	    *ptr = '\0';
	else if ((ptr = index(buf, '\n')) != NULL)/* zap trailing newline */
	    *ptr = '\0';
		
	/* decode instruction 
	*/

	ip = buf;		/* start at the beginning of the line */
	op = -1;		/* Invalid op-code */
    
	while (*ip && iswhite(*ip))/* skip leading whitespace */
	    ip++;

	if (ip == ptr || *ip == '\0') {	/* it's a 'blank' line */
	    if (ptr != NULL)
		*ptr = COMCHAR;	/* put comment back */
	    if (listflag)
		printf("%04d %s",r,buf);
	    continue;		/* go to next line */
	}

	for (op = TOPOP; op >= 0 && strncmp(ip,op_str[op],3) != 0 ; op--)
	    ;			/* find that opcode */

	if (op == -1) {		/* opcode not yet implimented! */
	    fprintf(stderr,"SYNTAX ERROR: Bad opcode %s", buf);
	    error = TRUE;
	}

	mem[r].op = op;		/* load the operator into <mem> */
	ip += 3;		/* skip over mnemonic to rest of line */
    
	while (*ip && iswhite(*ip))/* skip whitespace */
	    ip++;

        /* figure out addressing mode for operand A
	*/

	switch (op) {
	    case JMP:
		if (*ip == '#') {
		    fprintf(stderr,"ERROR: JMP, immediate mode operand\n");
		    error = TRUE;
		    break;
		}
		if (*ip == '@') {
		    ip++;
		    mem[r].mode[A] = INDIRECT;
		}		 /* DIRECT mode is the initial condition */
		mem[r].arg[A] = atoi(ip);
		while (mem[r].arg[A] < 0)	/* scroll up */
		    mem[r].arg[A] += MEMSIZE;
		break;
	    case DAT:
		if (*ip == '@') {
		    fprintf(stderr,"ERROR: DAT, indirect mode operand\n");
		    error = TRUE;
		    break;
		}
		if (*ip == '#')
		    ip++;	/* ignore this mode, argue later */
		mem[r].arg[B] = atoi(ip);
		while (mem[r].arg[B] < 0)	/* scroll up */
		    mem[r].arg[B] += MEMSIZE;
		break;
	    default:
		for (i = A; i<= B ; i++) {
		    if (!*ip) {
			fprintf(stderr,"ERROR: Two Arguments Required\n");
			error = TRUE;
			break;	/* break out of the loop */
		    }
		    if (*ip == '#') {
			mem[r].mode[i] = IMMEDIATE;
			ip++;
		    }
		    else if (*ip == '@') {
			mem[r].mode[i] = INDIRECT;
			ip++;
		    };
		    /* DIRECT mode is the default */

		    mem[r].arg[i] = atoi(ip);

		    while (mem[r].arg[i] < 0)
			mem[r].arg[i] += MEMSIZE;
		    while (*ip && !(iswhite(*ip)))
			ip++;
		    while (*ip && iswhite(*ip))
			ip++;
		}/* for */
		break;
	}/* switch */

	if (op != DAT && start == 0)
	    start = r;		/* first executable statement */

	/* Do listing stuff...
	*/

	if (ptr != NULL)
	    *ptr = COMCHAR;	/* put comment back */

	if (listflag)
	    printf("%04d %s  %s", r, pr_inst(mem[r]), buf);

	if (++r >= (sp + MAXPROGSIZE)){/* increment and check scroll */
	    fprintf(stderr,"Program %s hogged too much stack",filename);
	    (void)exit(3);
	}
    }

    sp = r;

    if (listflag)
	(void)fflush(stdout);

    (void)fclose(f);

    return(start);/* return starting address */
}

'poobahfig'
echo Extracting do.c
cat <<'poobahfig' > do.c
/*
 *	do.c	this module executes the opcodes
 */

#include <stdio.h>
#include "cw.h"

/*
 * execute()	Execute the two loaded Redcode programs starting at 
 *		addresses pc1 and pc2 until one executes an illegal 
 *		instruction.  Return the winner.
 */

execute(pc1, pc2)
register address pc1,
	         pc2;
{
    printf("executing: pc1 = %d, pc2 = %d\n\n", pc1, pc2);
    for (EVER){
	if ((pc1 = do_instruction(pc1)) < 0)/* Execution error */
	    return(2);

	if (pc1 >= MEMSIZE)		/* scroll around */
	    pc1 %= MEMSIZE;

	if (traceflag)	/* separate the two instruction traces */
	    printf("\t||\t");

	if ((pc2 = do_instruction(pc2)) < 0)/* Execution error */
	    return(1);

	if (pc2 >= MEMSIZE)
	    pc2 %= MEMSIZE;

    /* do_instruction prints a trace, which needs to have a newline here 
    */
	if (traceflag)
	    putchar('\n');
    }
}

/*
 * do_instruction()	interprets one instruction at <addr>, and
 *			returns the address of next instruction to
 * 			be executed or -1 if illegal instruction.
 */

do_instruction(addr)
register address addr;
{
    if (traceflag)
	printf("@ %04d", addr);

    (void)fflush(stdout);
 
    if (traceflag)	/* a little different than pr_inst */
	printf("  %s %c%-4d, %c%-4d", op_str[mem[addr].op], 
		mode_char[mem[addr].mode[A]], mem[addr].arg[A],
		mode_char[mem[addr].mode[B]], mem[addr].arg[B]);

    (void)fflush(stdout);

    switch (mem[addr].op) {
	case MOV: 
	    if (do_mov(addr) == 0)
		return(++addr);
	    else
		return(-1);
	case ADD: 
	    if (do_add(addr) == 0)
		return(++addr);
	    else
		return(-1);
	case SUB: 
	    if (do_sub(addr) == 0)
		return(++addr);
	    else
		return(-1);
	case JMP: 
	    return(do_jmp(addr));
	case JMZ: 
	    switch (mem[addr].mode[B]) {
		case INDIRECT:
		    if (mem[mem[addr].arg[B]].arg[B] == 0)
			return(do_jmp(addr));
		    else
			return(++addr);
		case DIRECT:
		    if (mem[addr + mem[addr].arg[B]].arg[B] == 0)
			return(do_jmp(addr));
		    else
			return(++addr);
		default:			/* IMMEDIATE */
		    if (mem[addr].arg[B] == 0)
			return(do_jmp(addr));
		    else
			return(++addr);
	    }
	case JMG: 
	    switch (mem[addr].mode[B]) {
		case INDIRECT:
		    if (mem[mem[addr].arg[B]].arg[B] > 0)
			return(do_jmp(addr));
		    else
			return(++addr);
		case DIRECT:
		    if (mem[addr + mem[addr].arg[B]].arg[B] > 0)
			return(do_jmp(addr));
		    else
			return(++addr);
		default:			/* IMMEDIATE */
		    if (mem[addr].arg[B] > 0)
			return(do_jmp(addr));
		    else
			return(++addr);
	    }
	case DJZ: 
	    switch (mem[addr].mode[B]) {
		case INDIRECT:
		    if (--mem[mem[addr].arg[B]].arg[B] == 0)
			return(do_jmp(addr));
		    else
			return(++addr);
		case DIRECT:
		    if (--mem[addr + mem[addr].arg[B]].arg[B] == 0)
			return(do_jmp(addr));
		    else
			return(++addr);
		default:			/* IMMEDIATE */
		    if (--mem[addr].arg[B] == 0)
			return(do_jmp(addr));
		    else
			return(++addr);
	    }
	case CMP: 
	    return(addr + do_cmp(addr));
	case DAT: 
	default: 
	    printf("\nIllegal instruction %s @ %d\n", pr_inst(mem[addr]), addr);
	    return(-1);
    }
}

/*
 *	do_add()	adds to operands, returns 0 on success,
 *			1 on error.
 */

do_add(addr)
register address addr;
{
    register address src, dest;
    memword data;

    data.op = 0;
    data.mode[A] = data.mode[B] = 0;
    data.arg[A] = data.arg[B] = 0;

    switch (mem[addr].mode[A]) {
	case IMMEDIATE: 
	    data.arg[B] = mem[addr].arg[A];
	    break;
	case DIRECT: 
	    data = mem[(addr + mem[addr].arg[A]) % MEMSIZE];
	    break;
	case INDIRECT: 
	    src = mem[(addr + mem[addr].arg[A]) % MEMSIZE].arg[B];
	    data = mem[(src + addr + mem[addr].arg[A]) % MEMSIZE];
	    break;
	default: 		/* ERROR */
	    fprintf(stderr,"do_add: illegal addressing mode\n");
	    return(1);
    }
    switch (mem[addr].mode[B]) {
	case IMMEDIATE: 	/* error */
	    fprintf(stderr,"do_add: illegal immediate destination\n");
	    return(1);
	case DIRECT: 
	    mem[(addr + mem[addr].arg[B]) % MEMSIZE].arg[B] += data.arg[B];
	    break;
	case INDIRECT: 
	    dest = mem[(addr + mem[addr].arg[B]) % MEMSIZE].arg[B];
	    mem[(dest + addr + mem[addr].arg[B]) % MEMSIZE].arg[B] 
			+= data.arg[B];
	    break;
	default: 		/* ERROR */
	    fprintf(stderr,"do_add: illegal addressing mode\n");
	    return(1);
    }
    return(0);			/* sucessful execution */
}

/*
 *	do_cmp()	compare a and b, return 1 if same, 2 if different 
 */

do_cmp(addr)
register address addr;
{
    register address src, dest;
    memword data;

    data.op = 0;
    data.mode[A] = data.mode[B] = 0;
    data.arg[A] = data.arg[B] = 0;

    switch (mem[addr].mode[A]) {
	case IMMEDIATE: 
	    data.arg[B] = mem[addr].arg[A];
	    break;
	case DIRECT: 
	    data = mem[(addr + mem[addr].arg[A]) % MEMSIZE];
	    break;
	case INDIRECT: 
	    src = mem[(addr + mem[addr].arg[A]) % MEMSIZE].arg[B];
	    data = mem[(src + addr + mem[addr].arg[A]) % MEMSIZE];
	    break;
	default: 		/* ERROR */
	    fprintf(stderr,"do_cmp: illegal addressing mode\n");
	    return(1);
    }
    switch (mem[addr].mode[B]) {
	case IMMEDIATE: 	/* error */
	    if (data.arg[B] == mem[addr].arg[B])
		return(1);
	    else
		return(2);
	case DIRECT: 
	    if (data.arg[B] == mem[(addr + mem[addr].arg[B]) % MEMSIZE].arg[B])
		return(1);
	    else
		return(2);
	case INDIRECT: 
	    dest = mem[(addr + mem[addr].arg[B]) % MEMSIZE].arg[B];
	    if (data.arg[B] ==
			mem[(dest+addr+mem[addr].arg[B]) % MEMSIZE].arg[B])
		return(1);
	    else
		return(2);
	default: 		/* ERROR */
	    fprintf(stderr,"do_cmp: illegal addressing mode\n");
	    return(1);
    }
}

/*
 *	do_jmp()	returns the address jumped to
 */

address
do_jmp(addr)
address addr;
{
    switch (mem[addr].mode[A]) {
	case DIRECT:
	    return(addr + mem[addr].arg[A]);
	default:	/* INDIRECT */
	    return(addr + mem[mem[addr].arg[A]].arg[B]);
    }
}


/*
 *	do_mov()	moves operand A to operand B returning
 *			0 on success or 1 on error.
 */
 
do_mov(addr)
register address addr;
{
    register address src, dest;
    memword data;

    data.op = 0;
    data.mode[A] = data.mode[B] = 0;
    data.arg[A] = data.arg[B] = 0;

    switch (mem[addr].mode[A]) {
	case IMMEDIATE: 
	    data.arg[B] = mem[addr].arg[A];
	    break;
	case DIRECT: 
	    data = mem[(addr + mem[addr].arg[A]) % MEMSIZE];
	    break;
	case INDIRECT: 
	    src = mem[(addr + mem[addr].arg[A]) % MEMSIZE].arg[B];
	    data = mem[(src + addr + mem[addr].arg[A]) % MEMSIZE];
	    break;
	default: 		/* ERROR */
	    fprintf(stderr,"do_mov: illegal addressing mode\n");
	    return(1);
    }
    switch (mem[addr].mode[B]) {
	case IMMEDIATE: 	/* error */
	    fprintf(stderr,"do_mov: illegal immediate destination\n");
	    return(1);
	case DIRECT: 
	    mem[(addr + mem[addr].arg[B]) % MEMSIZE] = data;
	    break;
	case INDIRECT: 
	    dest = mem[(addr + mem[addr].arg[B]) % MEMSIZE].arg[B];
	    mem[(dest + addr + mem[addr].arg[B]) % MEMSIZE] = data;
	    break;
	default: 		/* ERROR */
	    fprintf(stderr,"do_mov: illegal addressing mode\n");
	    return(1);
    }
    return(0);			/* sucessful execution */
}

/*
 *	do_sub()	subtracts operand A from B putting the
 *			result in B. returning 0 on success or
 *			1 on error.
 */

do_sub(addr)
register address addr;
{
    register address src, dest;
    memword data;

    data.op = 0;
    data.mode[A] = data.mode[B] = 0;
    data.arg[A] = data.arg[B] = 0;

    switch (mem[addr].mode[A]) {
	case IMMEDIATE: 
	    data.arg[B] = mem[addr].arg[A];
	    break;
	case DIRECT: 
	    data = mem[(addr + mem[addr].arg[A]) % MEMSIZE];
	    break;
	case INDIRECT: 
	    src = mem[(addr + mem[addr].arg[A]) % MEMSIZE].arg[B];
	    data = mem[(src + addr + mem[addr].arg[A]) % MEMSIZE];
	    break;
	default: 		/* ERROR */
	    fprintf(stderr,"do_sub: illegal addressing mode\n");
	    return(1);
    }
    switch (mem[addr].mode[B]) {
	case IMMEDIATE: 	/* error */
	    fprintf(stderr,"do_sub: illegal immediate destination\n");
	    return(1);
	case DIRECT: 
	    mem[(addr + mem[addr].arg[B]) % MEMSIZE].arg[B] -= data.arg[B];
	    break;
	case INDIRECT: 
	    dest = mem[(addr + mem[addr].arg[B]) % MEMSIZE].arg[B];
	    mem[(dest + addr + mem[addr].arg[B]) % MEMSIZE].arg[B] 
		    -= data.arg[B];
	    break;
	default: 		/* ERROR */
	    fprintf(stderr,"do_sub: illegal addressing mode\n");
	    return(1);
    }
    return(0);			/* sucessful execution */
}


'poobahfig'
echo Extracting misc.c
cat <<'poobahfig' > misc.c
/*
 *	Misc.c	all sorts of miscellaneus goodies
 */

#include <stdio.h>
#include "cw.h"

/*
 *	clear_mem()	clear the simulated arena
 */

void
clear_mem() 
{
    register address i;

    for (i = 0; i < MEMSIZE; i++) { 
	mem[i].op = 0;
	mem[i].mode[A] = 0;
	mem[i].mode[B] = 0;
	mem[i].arg[A] = 0;
	mem[i].arg[B] = 0;
    }
}

/*
 *	dump()	dumps the stack without dumping thousands of 0's
 */

void
dump() 
{
    register address r;
    register int flag = 0;

    printf("\n\n---------- MEMORY DUMP -------------\n");
    for (r = 0; r < MEMSIZE; r++) {
	if (iszero(mem[r])) {
	    switch (flag) {
		case 0:
		    continue;	/* next r, don't dump thousands of 0's */
		case 1:
		    printf(" *\n");
		    flag = 0;
		    break;
		default:
		    printf("%05d 000   0000  0000\n", r);
		    flag = 1;
	    }
	} else {
	    printf("%05d %s\n", r, pr_inst(mem[r]));
	    flag = 2;
	}
    }
}

/*
 *	draw()	take care of tie conditions, timeing out
 */

int
draw()
{
    printf("\nBattle is a DRAW -- timed out after %d seconds\n", TIMEOUT);
    if (dumpflag)
	dump();
    (void)exit(0);
}

/*
 *	*pr_inst()	returns a formatted character buffer representing
 *			the corewar memory element x
 */

char   
*pr_inst(x)
memword x;
{
    char    buf[128];

    (void)sprintf(buf, "%3s  %1c%04d %c%04d", op_str[x.op], 
		mode_char[x.mode[A]], x.arg[A], mode_char[x.mode[B]], x.arg[B]);
    return(buf);
}

/*
 *	usage()		usage message
 */

void
usage()
{
    fprintf(stderr,"Usage: %s %s\n", PROGRAM, USAGE);
    exit(-1);
}

'poobahfig'
echo Extracting dwarf
cat <<'poobahfig' > dwarf
dat	-1	; target for dwarf's little 0 rocks
add	#5, -1	; increase the target
mov	#0, @-2 ; bombs away!
jmp	-2	; loop back
'poobahfig'
echo Extracting gemini
cat <<'poobahfig' > gemini
; Gemini
;	copies itself ahead
;
dat	0	    ; pointer to source address
dat	99	    ;  pointer to destination address
mov	@-2, @-1    ; copy source to destination
cmp	-3, #9	    ; if all 10 lines have been copied
jmp	4	    ;    then leave the loop
add	#1, -5	    ; else, increment the source address
add	#1, -5	    ;    and the destination address
jmp 	-5	    ;    and return to the loop
mov	#99, 93	    ; restore the starting destination address
jmp	93	    ; jump to the new copy
'poobahfig'
echo Extracting imp
cat <<'poobahfig' > imp
mov	0, 1	; copy myself one instruction ahead
'poobahfig'
echo Extracting wcount
cat <<'poobahfig' > wcount
wc -l main.c load.c do.c misc.c cw.h global.h machdep.h      
     154 main.c
     193 load.c
     361 do.c
      96 misc.c
     120 cw.h
      37 global.h
      18 machdep.h
     979 total
'poobahfig'
echo Extracting backz
cat <<'poobahfig' > backz
dat		-1
mov	1	@-1
djz	0	-2
jmp	-2
'poobahfig'
echo Extracting bigfoot
cat <<'poobahfig' > bigfoot
dat   0          ;pointer to source address
dat   1752       ;pointer to destination address
mov   @-2, @-1   ;copy source to destination
cmp   -3, #9     ;if all 10 lines have been copied...
jmp   4          ;...then leave the loop
add   #1, -5     ;otherwise, increment the source address
add   #1, -5     ;...and the destination address
jmp   -5         ;...and return to the loop
mov   #1752,1746 ;restore the starting destination address
jmp   1746       ;jump to the new copy
'poobahfig'
echo Extracting doc.6
cat <<'poobahfig' > doc.6
.TH COREWARS 6 
.UC 4
.SH NAME
corewars \- battling programs
.SH SYNOPSIS
.B corewars
[
.B \-cdlot
]
prog1 [prog2]
.br
.SH DESCRIPTION
.I Corewar
loads 
.I prog1
and
.I prog2
into the simulated memory arena and executes instructions for 
each in turn until one encounters an illegal instruction, at which
point the other is declared the winner.
If neither has won in two minutes, the match is declared a draw.
.PP
.I Corewars
is based on A.K Dewdeney's May 1984 column in Scientific American.
.PP
.B Options
.PP
.B \-c
suppress execution of the programs, allowing the loader to
check for syntax errors.
.PP
.B \-d
causes a post mortem memory dump to be written on the standard output.
.PP
.B \-l
causes a listing of the generated code to be written on the
standard output when each file is loaded.
.PP
.B \-o
informs corewars that only one program will be loaded, this
sets the 
.B \-c
flag.
.PP
.B \-t
causes an instruction execution trace to be written on the standard output.
.SH AUTHORS
Berry Kercheval (ihnp4!zehntel!berry)

tailor: Jim of HCDE

.PP
.SH FILES
/usr/games/corewars	Default save file
.SH BUGS
.PP
None yet known

'poobahfig'