sbarr@hawk.ulowell.edu (bot man) (05/31/90)
#!/bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #!/bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # Makefile # READ_ME # bdwarf.rc # cw.6 # cw.h # dwarf.rc # fibo.rc # gemini.rc # getopt.c # imp.rc # mars.c # movmem.c # msg.c # print.c # random.rc # rcasm.l # rcasm.l.old # rcasm.y # scheduler.c # stomper.rc # sum.c # unrc.c # vdisplay.c # vstatus.c # This archive created: Tue Mar 3 18:14:02 1987 export PATH; PATH=/bin:$PATH if test -f 'Makefile' then echo shar: over-writing existing file "'Makefile'" fi cat << \SHAR_EOF > 'Makefile' # # Makefile for Corewar system # #static char rcsid[] = "$Header: Makefile,v 7.0 85/12/28 14:35:38 ccohesh Dist $"; # # [cw by Peter Costantinidis, Jr. @ University of California at Davis] # # # If you are running under SysV, I am told that you would want to # uncomment the following commented lines. # # .SUFFIXES: .rc # .rc: # rcasm $< $@ HDRS = Makefile cw.h YSRC = rcasm.y LSRC = rcasm.l SRCS = getopt.c mars.c movmem.c msg.c print.c scheduler.c sum.c\ vdisplay.c vstatus.c OBJS = getopt.o mars.o movmem.o msg.o print.o scheduler.o sum.o\ vdisplay.o vstatus.o PROGS = bdwarf.rc dwarf.rc fibo.rc gemini.rc imp.rc\ random.rc stomper.rc # # libs # CWLIB = cw.a CRLIB = -lcurses TERMLIB = -ltermlib ALLLIBS = $(CWLIB) $(CRLIB) $(TERMLIB) # # It has been suggested that FLAGS should include "-DSYS5" when running # under SYS5 # FLAGS = #-DDEBUG CFLAGS = -O $(FLAGS) LDFLAGS = -o $@ LINTARGS= -ahxc $(DEFS) -DLINT SHAR = shar SHAROUT = cw.shar ALLSRCS = $(HDRS) $(SRCS) unrc.c cw.6 $(YSRC) $(LSRC) ALLEXES = rcasm unrc mars ALL = READ_ME $(ALLSRCS) $(CWDOC) CI = ci -u NAME = mars ALLDEMOS= imp dwarf gemini stomper demo: mars rcasm # # You may want to comment out the "rcasm" lines if # running SysV. # rcasm imp.rc imp rcasm dwarf.rc dwarf rcasm gemini.rc gemini rcasm stomper.rc stomper mars -p imp dwarf gemini stomper install: mars rcasm unrc cw.nr cw.nr: cw.6 tbl cw.6 | nroff -man | col > cw.nr mars: $(CWLIB) cc $(LDFLAGS) $(ALLLIBS) # # RCS stuff # ci: $(ALLSRCS) -$(CI) $? @touch ci coall: co -l $(ALLSRCS) update: ci -sDist -u -f$(VERS) $(ALLSRCS) @touch ci all: $(ALLEXES) $(CWLIB): $(OBJS) @ar rv $@ $?; ranlib $@ $(OBJS): $(HDRS) rcasm: rcasm.o $(CWLIB) rcasm.h cc $(LDFLAGS) rcasm.o $(CWLIB) -ll rcasm.o: rcasm.c rcasm.h $(HDRS) rcasm.h: $(LSRC) $(HDRS) $(LEX) $(LFLAGS) $(LSRC) @mv lex.yy.c rcasm.h rcasm.c: $(YSRC) $(HDRS) $(YACC) $(YFLAGS) $(YSRC) @mv y.tab.c rcasm.c unrc: unrc.o $(CWLIB) cc -O $(LDFLAGS) unrc.o $(CWLIB) unrc.o: $(HDRS) lint: lint $(LINTARGS) $(SRCS) print: lpr -Pc -p Makefile $(ALLSRC) tags: $(HDRS) $(SRCS) ctags -u $? sort tags -o tags wc: wc $(ALLSRCS) export: $(SHAR) $(ALL) $(PROGS) > $(SHAROUT) clean: rm -f $(OBJS) rcasm.c rcasm.h $(ALLDEMOS) $(ALLEXES) SHAR_EOF if test -f 'READ_ME' then echo shar: over-writing existing file "'READ_ME'" fi cat << \SHAR_EOF > 'READ_ME' This is the second source distribution of the Core Wars. Some of the bugs that have been fixed: 1. unrc.c has been modified to recognize the MUL, DIV and RND instructions. 2. cw.6 had some problems with the tables. These have been solved. 3. The RND instruction no longer causes a job to halt. 4. A bug in the lexical analyzer where the toggle variable "toggle" wasn't being toggled has been corrected. For further reading on the origins and purpose of this system, please see the the "SEE ALSO" section of the documentation. Please send all new bug reports to the author. ------------------------------------------------------------------------------- Wed Dec 11 18:26:00 PST 1985 This is the first source distribution of the game of Core Wars. This game has been tested on BSD4.2 UNIX. It should run under any UNIX system that has curses, lex and yacc and virtual memory and whose compiler allows bitfields in structures. If your system does not have virtual memory but does have separate I and D space, you should insert the appropriate loader options in the Makefile. You may also have to decrease "MAX_MEM" and make the corresponding changes to the bitfield widths. I think that it would be great if we could have world wide competition playing this game. Perhaps people could post their best redcode code to net.sources.games. Perhaps an unbeatable program might evolve. Peter Costantinidis, Jr. ...!ucbvax!ucdavis!deneb!ccohesh001 SHAR_EOF if test -f 'bdwarf.rc' then echo shar: over-writing existing file "'bdwarf.rc'" fi cat << \SHAR_EOF > 'bdwarf.rc' / bdwarf.rc - backwards moving dwarf $LOOP: SUB #8 $WHERE / won't kill eachother MOV #-3 @$WHERE JMP $LOOP $WHERE: DAT -8 / change this to a 4 and dwarf's SHAR_EOF if test -f 'cw.6' then echo shar: over-writing existing file "'cw.6'" fi cat << \SHAR_EOF > 'cw.6' .\" Documentation for Corewars system .\" .\" static char rcsid[] = "$Header: cw.6,v 7.2 86/01/06 21:28:21 ccohesh Exp $"; .\" .TH CW UCD "2 December 1985" .SH NAME mars, rcasm, unrc \- Core Wars simulation system .SH SYNOPSIS .B mars [ .B \-dilpv ] [ .B \-rn ] [ .B \-sn ] [ .B \-cn ] file file ... .br .B rcasm file [ofile] .br .B unrc file .SH OPTIONS .TP .B \-d Do not print the status window if in visual display mode. .TP .B \-i Print current instruction. This turns on the .B \-p and the .B \-v options. .TP .B \-l Print job size and load location during startup. .TP .B \-p Print the current cycle number. .TP .B \-rn Set the seed for the random number generator to .B n. If .B n is zero, then .B mars will create its own seed and print it. .TP .B \-sn Set the minimum amount of memory initially separating jobs to .B n memory pages. A memory page is 16 words. This value must be less than 511. The default separation value is 8 pages. .TP .B \-cn Set the maximum number of execution cycles to .B n. The default value is 1024. .TP .B \-v Do not run in visual display mode. This is useful to quickly determine the outcome. Also, the instruction display will not work in visual display mode. .TP .SH DESCRIPTION .I Mars (an acronym for Memory Array Redcode Simulator) executes battle programs created by .I rcasm. The battle programs are entered into the battlefield at randomly chosen positions and executed in a simple version of time-sharing. Execution continues until all but one program is left running or the instruction cycle limit is reached. Programs are halted when they attempt to execute an invalid instruction or an instruction with an illegal addressing mode. When .I mars terminates it prints a summary of results of the battle indicating how long each job ran and the reason (if any) for a job's termination. .LP By default .I mars will display the battle using a box of 512 periods ('.'), each representing one memory page of 16 memory locations. The position of each program's program counter is marked by a capital letter and the areas affected by the program executing the "MOV" instruction by the corresponding lowercase letter. An optional status window is displayed to the right of this box. Each line in the window contains information for one program. This information includes the letter representing the program, the `name' of the program (via the command line argument) and the program's current status. If the .B \-p option is specified on the command line the bottom line of the status window will indicate the number of cycles elapsed and the number of programs still operational. .LP .I Rcasm assembles the named .I redcode assembly language .I file. The output of the assembly is left on the file .I ofile; if that is ommitted, .I rc.out is used. .LP .I Unrc dis-assembles the named .I redcode object file writing the .I redcode assembly instructions to the standard output. However, be aware that since .I rcasm does not include comments in the object files that it creates, the output from .I unrc will not contain any comments that once might have been in the original source core. .SH DETAILS The size of the memory into which the programs are loaded is 8192 words. This is divided into 512 16 word pages. Jobs are loaded on page boundaries with the default minimum separation between programs being 8 pages. Since jobs are loaded on page boundaries they can work in teams (i.e. employ strategies such that if two jobs of the same type are loaded they will only kill jobs of a different type). This is obvious in the .B dwarf program. If one .B dwarf job can not kill itself it will not be able to kill other .B dwarfs. This isn't necessarily true for programs that use the .B RND instruction. .LP None of the programs know where the other ones are, they do not even know how many other programs exist. Because a program can never refer to an absolute address, some addressing modes for some operands do not make sense. All memory addressing is relative to the current instruction. Since memory is `circular', addressing location 8192 would be the same as addressing location 0. .LP Since execution of a program starts on its first instruction, the user is cautioned to not have any .B DAT instructions at this point. If a user prefers to place all his .B DAT instructions at the beginning of his program, it is suggested that he precede them with a .B JMP instruction to the appropriate address. .SH REDCODE .TS center tab(:); c s s s c c s c. Redcode Instruction Set = Mnemonic:Arguments:Action Symbol:: _ .T& lw(0.35i) cw(0.25i) cw(0.25i) lw(4i). DAT::B:T{ Initialize location to value B. T} MOV:A:B:T{ Move A into location B. T} ADD:A:B:T{ Add operand A to contents of location B and store result in location B. T} SUB:A:B:T{ Subtract operand A from contents of location B and store result in location B. T} JMP::B:T{ Jump to location B. T} JMZ:A:B:T{ If operand A is 0, jump to location B; otherwise continue with next instruction. T} DJZ:A:B:T{ Decrement contants of location A by 1. If location A now holds 0, jump to location B; otherwise continue with next instruction. T} CMP:A:B:T{ Compare operand A with operand B. If they are not equal, skip next instruction; otherwise continue with next instruction. T} MUL:A:B:T{ Multiply operand B by operand A and store result in location B. T} DIV:A:B:T{ Divide operand B by operand A and store result in location B. T} RND::B:T{ Chose a random integer between 0 and the maximum memory size and store it in location B. T} .TE .sp 2 .TS center tab(:); c s s c c c. Redcode Addressing Modes = Mnemonic:Name:Meaning Symbol:: _ .T& c l lw(4.0i). #:Immediate:T{ The number following this symbol is the operand. T} <none>:Relative:T{ The number specifies an offset from the current instruction. Mars adds the offset to the address of the current instruction; the number stored at the location reached in this was is the operand. T} @:Indirect:T{ The number following this symbol specifies an offset from the current instruction to a location where the relative address of the operand is found. Mars adds the offset to the address of the current instruction and retrieves the number stored at the specified location; this number is the interpreted as an offset from its own address. The number found at this second location is the operand. T} .TE .LP Labels are another feature of this assembly language. Labels consist of alphanumerical characters witha maximum length of six characters starting with a dollar sign ('$'). To declare a label, simply place the label with a colon (':') appended to it at the beginning of an instruction. Labels can be used anywhere where you would normally specify an integer address. .SH EXAMPLES .ta 1.5i 2.0i 2.25i JMP $START .br $ADDR: DAT 0 .br $START: ADD #8 $ADDR .br MOV #0 @$ADDR .br JMP $START .LP This is a simple program, usually refered to as .B Dwarf. It works its way through memory bombarding every eighth memory address with a zero. .LP An even simpler program, .B imp, simply copies itself throughout memory, one memory location at a time. .br $ME: MOV $ME $AFTERME $AFTERME: DAT 0 .SH FILES .ta 1.5i rc.out default resultant object file .SH "SEE ALSO" D. G. Jones and A. K. Dewdney, "CORE WAR GUIDELINES." .br A. K. Dewdney, "Computer Recreations," .I Scientific American, May, 1984, pp. 14-23 .SH DIAGNOSTICS .B Rcasm will complain if it discovers syntax errors in the input file. .B Unrc will complain if the input file contains invalid redcode instructions. .B Mars will complain about argument syntax errors and files that it cannot open. .SH AUTHOR Peter Costantinidis, Jr., University of California, Davis .SH BUGS None known at this time. When they are discovered the author would appreciate notification. SHAR_EOF if test -f 'cw.h' then echo shar: over-writing existing file "'cw.h'" fi cat << \SHAR_EOF > 'cw.h' /* ** cw.h - misc. constants and macros used throughout corewar system ** ** [cw by Peter Costantinidis, Jr. @ University of California at Davis] */ /* ** static char rcsid[] = "$Header: cw.h,v 7.0 85/12/28 14:35:45 ccohesh Dist $"; ** */ #include <sys/types.h> /* necessary for void */ #ifdef BSD42|BSD43 # define SETJMP _setjmp # define LONGJMP _longjmp #else # define SETJMP setjmp # define LONGJMP longjmp #endif /* ** curses conflicts */ #ifndef WINDOW # define TRUE 1 # define FALSE 0 # undef reg #endif #ifdef DEBUG # define reg #else # define reg register #endif #ifndef CTRL # define CTRL(c) ('c'&037) #endif #ifndef CINTR # define CINTR CTRL(?) #endif #define min(a,b) ((a) < (b) ? (a) : (b)) #define max(a,b) ((a) > (b) ? (a) : (b)) #define abs(a) ((a) < 0 ? -(a) : (a)) /* ** Visual display related constants */ #define MIN_LINES 24 /* minimum lines allowed in display */ #define MIN_COLS 80 /* minimum columns allowed in display */ /* ** memory window */ #define MLINES 16 /* # lines in memwin */ #define MCOLS (MAX_MEM/(MLINES*NUMMEM))/* # columns in memwin */ #define MYBEGIN 1 /* y offset in stdscr of memwin */ #define MXBEGIN 1 /* x offset in stdscr of memwin */ /* ** message window */ #define MSGLINES (MIN_LINES-MLINES-2)/* lines in status window */ #define MSGCOLS (MXBEGIN+MCOLS)/* columns in status window */ #define MSGYBEGIN (MYBEGIN+MLINES+1)/* y offset in stdscr of status win */ #define MSGXBEGIN 0 /* ** status window */ #define SLINES MIN_LINES #define SCOLS (MIN_COLS-MCOLS-2) #define SYBEGIN 0 #define SXBEGIN (MXBEGIN+MCOLS+1) #define NUMMEM PAGESIZE/* # memwords per character in memwin */ #define HORTBORDER '-' /* horizontal border char for memwin box */ #define VERTBORDER '|' /* vertical border char for memwin box */ /* ** misc. characters in memory window */ #define MEMPTY '.' /* nothing of note about memsect */ #define MSHARE '-' /* more than one job writing */ #define MHIT '+' /* hit near a PC */ #define MFULL '*' /* >=10 PC's in memsect */ /* ** output controls */ #define SIZE_START 0x0001L /* print size and start of job */ #define PASSNUM 0x0002L /* print current cycle */ #define PASSFREQ 10 /* print every n cycles */ #define PINST 0x0004L /* print current instruction */ #define VISUAL 0x0008L /* visual display */ #define STATUS 0x0010L /* status window for v.d. */ #define DEF_CTRLS (VISUAL|STATUS|PINST) #define ON(x) (octrl&(x)) #define TOGGLE(x) octrl=(octrl&x)?(octrl&~x):(octrl|x) #define HALTED(j) (j->pdied) #define PC _pc #define uns unsigned #define unss unsigned short #define when break;case #define otherwise break;default #define RC_OUT "rc.out" /* ** memory constraints and other limits */ #define PAGESIZE 16 /* jobs placed on page boundaries */ #define MAX_PAGE 512 /* max. pages in mem. */ #define MAX_MEM (PAGESIZE*MAX_PAGE)/* size of mem. */ #define JMAX_LEN 512 /* max. len for job */ #define PAGESEP 8 /* min. job separation in pages */ #define JOB_WIDTH (JMAX_LEN+ (PAGESEP*PAGESIZE)) #define CYCLES 1024 /* max. execution cycle limit */ #define MAX_USERS (SLINES-1)/* max. # jobs (some might not fit...) */ #define MAX_LABELS 128 /* maximum number of labels allowed */ #define LABEL_LEN 6 /* max. len of labels */ /* ** field bit-widths needed */ #define OP_BITS 4 #define MODE_BITS 2 #define ADDR_BITS 13 /* # of bits needed to address all memory */ /* ** Redcode instruction set */ #define DAT 0 /* initialize location to value B */ #define MOV 1 /* move A into location B */ #define ADD 2 /* add A to contents of B, results in B */ #define SUB 3 /* subtract A from contents of B, results in B */ #define JMP 4 /* jump to B */ #define JMZ 5 /* if A == 0 then jump to B, otherwise continue */ #define DJZ 6 /* --A; if A == 0 then jump to B */ #define CMP 7 /* compare A with B; if != then skip next instruction */ #define MUL 8 /* multiply B by A, results in B */ #define DIV 9 /* divide B by A, results in B */ #define RND 10 /* random number between 0 and MAX_MEM, results in B */ /* ** Addressing modes */ #define IMM 0 /* number is operand */ #define REL 1 /* number specifies offset from current instruction */ #define IND 2 /* number specifies offset from current instruction */ /* to location where relative address of operand is */ /* found */ /* ** character and string constants representing the various modes ** and instructions */ #define CIMM '#' #define CREL ' ' #define CIND '@' #define SDAT "DAT" #define SMOV "MOV" #define SADD "ADD" #define SSUB "SUB" #define SJMP "JMP" #define SJMZ "JMZ" #define SDJZ "DJZ" #define SCMP "CMP" #define SMUL "MUL" #define SDIV "DIV" #define SRND "RND" /* ** termination reasons for mars/processes */ #define EALIVE 0 /* currently active */ #define ECYCLE 1 /* max cycle limit exceeded */ #define EWIN 2 /* normal termination (a winner) */ #define EILLINST 3 /* illegal instruction */ #define EBADMODE 4 /* invalid addressing mode */ #define EINTERRUPT 5 /* process interrupted */ typedef struct { uns op:OP_BITS, /* opcode */ moda:MODE_BITS, /* mod argument A */ modb:MODE_BITS, /* mod argument B */ arga:ADDR_BITS, /* argument A */ argb:ADDR_BITS; /* argument B */ } memword; #define val argb typedef struct { char *pname; /* name of player (input file name) */ int pid; /* process number */ int pc; /* current program counter */ int psize; /* # of instruction in program */ int picnt; /* # of instructions executed at job halt */ int pdied; /* non-zero if dead, if dead then reason */ memword *plstmem; /* # of last memword modified */ } process; extern char *argv0; extern int jobcnt, jobsleft, min_sep; extern int cycle, max_cyc; extern long octrl; extern memword memory[]; extern char *strcpy(); extern char *diedstr(), *punctrl(); extern void usage(), msg(), msgfini(), movmem(), statfini(), vfini(), vstatus(), vstajob(); extern int printit(), sum(), msginit(), statinit(), vupdate(); SHAR_EOF if test -f 'dwarf.rc' then echo shar: over-writing existing file "'dwarf.rc'" fi cat << \SHAR_EOF > 'dwarf.rc' / dwarf.rc $BEGIN: ADD #8 $WHERE / won't kill eachother MOV #-3 @$WHERE JMP $BEGIN $WHERE: DAT -1 / change this to a 0 and dwarf's / will not kill eachother SHAR_EOF if test -f 'fibo.rc' then echo shar: over-writing existing file "'fibo.rc'" fi cat << \SHAR_EOF > 'fibo.rc' / fibo.rc - / / f(0) = 0 / f(1) = 1 / f(n) = f(n-1) + f(n-2) / $START: jmz $TOG $L2 $HERE: mov #$HERE $TOG / toggle tog add $1 $2 mov 0 @$2 jmp $START $L2: mov 1 $TOG add $2 $1 mov 0 @$1 jmp $START $TOG: dat 0 $1: dat 1 $2: dat 1 SHAR_EOF if test -f 'gemini.rc' then echo shar: over-writing existing file "'gemini.rc'" fi cat << \SHAR_EOF > 'gemini.rc' / gemini.rc - copy program and jump to new copy jmp $START /jump to start of program $SRC: dat 0 /pointer to source address $DST: dat 99 /pointer to dest. address $START: mov @$SRC @$DST /copy source to dest. cmp $SRC #11 /if all 10 lines have been copied... jmp $DONE /...then leave the loop add #1 $SRC /otherwise, increment the source address add #1 $DST /...and the dest. address jmp $START /...and return to the loop $DONE: mov #99 93 /restore the starting dest. address jmp 93 /jump to the new copy SHAR_EOF if test -f 'getopt.c' then echo shar: over-writing existing file "'getopt.c'" fi cat << \SHAR_EOF > 'getopt.c' /* ** getopt.c - argument parser ** static char rcsid[] = "$HEADER$"; ** */ #include "cw.h" /*LINTLIBRARY*/ #ifndef EOF # define EOF -1 #endif #ifndef SYSV # define strchr index #endif #define ERR(s, c) if(opterr){\ extern int strlen(), write();\ char errbuf[2];\ errbuf[0] = c; errbuf[1] = '\n';\ (void) write(2, argv[0], (unsigned)strlen(argv[0]));\ (void) write(2, s, (unsigned)strlen(s));\ (void) write(2, errbuf, 2);} extern int strcmp(); extern char *strchr(); static int opterr = 1; int optind = 1; static int optopt; char *optarg; int getopt (argc, argv, opts) int argc; char **argv, *opts; { static int sp = 1; reg int c; reg char *cp; if (sp == 1) { if (optind >= argc || argv[optind][0] != '-' || !argv[optind][1]) return(EOF); if (!strcmp(argv[optind], "--")) return(optind++, EOF); } optopt = c = argv[optind][sp]; if (c == ':' || !(cp=strchr(opts, c))) { ERR(": illegal option -- ", c); if (!argv[optind][++sp]) optind++, sp = 1; return('?'); } if (*++cp == ':') { if (argv[optind][sp+1]) optarg = &argv[optind++][sp+1]; else if (++optind >= argc) { ERR(": option requires an argument -- ", c); sp = 1; return('?'); } else optarg = argv[optind++]; sp = 1; } else { if (!argv[optind][++sp]) { sp = 1; optind++; } optarg = (char *) 0; } return(c); } SHAR_EOF if test -f 'imp.rc' then echo shar: over-writing existing file "'imp.rc'" fi cat << \SHAR_EOF > 'imp.rc' / imp.rc - move everywhere, one instruction at a time $START: mov $START $END $END: dat 0 SHAR_EOF if test -f 'mars.c' then echo shar: over-writing existing file "'mars.c'" fi cat << \SHAR_EOF > 'mars.c' /* ** mars.c - corewar machine interpreter ** ** [cw by Peter Costantinidis, Jr. @ University of California at Davis] */ #include <stdio.h> #include <setjmp.h> #include <signal.h> #include "cw.h" static char rcsid[] = "$Header: mars.c,v 6.0 85/12/13 00:31:16 ccohesh001 Dist $"; char *argv0; int jobcnt = 0; /* # of jobs */ int jobsleft; /* # of jobs left running */ int min_sep = PAGESEP; /* initial min. dist. between jobs */ int max_cyc = CYCLES; /* min. # of process cycles */ int cycle; /* # of cycles */ static process pcs[MAX_USERS]; /* ** the following variables are used globally and rarely passed ** to any other functions */ long octrl = DEF_CTRLS; /* output control variable */ memword memory[MAX_MEM+1]; extern void fini(), init(), randomize(), trap(), zeromem(); extern int pcscompar(); extern char *diedstr(); /* ** main() - the main program ** - parse arguments, call initialization routines, start game ** and call de-initialization routines */ main (argc, argv) reg int argc; reg char **argv; { reg int i; auto int arg; extern int optind; argv0 = *argv; while ((arg = getopt(argc, argv, "s:c:dlipvr:")) != EOF) { switch (arg) { extern char *optarg; when 'r': /* randomize */ if (*optarg == '0') randomize(0); else randomize(atoi(optarg)); when 's': /* separation */ if ((min_sep = atoi(optarg)) < 0) min_sep = 1; else if (min_sep > (MAX_PAGE-1)) { fprintf(stderr, "%s: separation too large (must be < %d)\n", argv0, MAX_PAGE-1); usage(); } when 'c': /* cycles */ max_cyc = atoi(optarg); when 'd': /* status window display */ TOGGLE(STATUS); when 'l': /* print starting stats */ TOGGLE(SIZE_START); when 'i': /* print instructions */ TOGGLE(PINST); when 'p': /* don't print cycle # */ TOGGLE(PASSNUM); when 'v': /* visual display */ TOGGLE(VISUAL); otherwise: case '?': usage(); } } argc -= optind, argv += optind; if (argc < 2) { fprintf(stderr, "%s: missing file arguments\n", argv0); usage(); } if (ON(VISUAL) && ON(PINST)) TOGGLE(PINST); if (ON(PINST)) octrl |= PASSNUM; zeromem(); if (ON(SIZE_START)) printf("%d words of memory available\n", MAX_MEM); if (argc > MAX_USERS) { fprintf(stderr, "%s: only %d jobs at once\n", argv0, MAX_USERS); exit(1); } for (i=jobcnt=0; *argv && i<argc; i++, argv++, jobcnt++) { pcs[i].pname = *argv; pcs[i].pdied = EALIVE; pcs[i].picnt = 0; pcs[i].plstmem = (memword *) NULL; pcs[i].pid = jobcnt; if ((pcs[i].pc = get_start()) < 0) { fprintf(stderr, "%s: not all jobs will fit\n", argv0); exit(1); } if (!(pcs[i].psize = load(pcs[i].pname, pcs[i].pc))) { fprintf(stderr, "%s: couldn't read in player \"%s\"\n", argv0, pcs[i].pname); exit(1); } if (ON(SIZE_START)) printf("Player \"%s\" @ %4d, size: %d\n", pcs[i].pname, pcs[i].pc, pcs[i].psize); } if (ON(SIZE_START)) { auto char buf[BUFSIZ]; printf("Hit return to continue"); gets(buf); } init(); fini(scheduler(pcs)); exit(0); } /* ** init() - perform various initializations */ static void init () { jobsleft = jobcnt; if (ON(VISUAL)) { if (vinit()) { fprintf(stderr, "%s: visual not working\n", argv0); exit(1); } if (ON(STATUS) && statinit(pcs)) { msg("Status window not working\n"); TOGGLE(STATUS); } } trap(0); if (!ON(VISUAL)) { auto char buf[BUFSIZ]; printf("Press return to start "); (void) gets(buf); return; } msg("Press any key to start"); getchar(); vupdate(pcs); } /* ** trap() - catches signals ** - signum is zero for the initial call, non-zero ** when an interrupt is recieved ** - when interrupt is received, call fini() */ static void trap (signum) reg int signum; { #ifndef LINT /* keeps lint from complaining */ signal(SIGINT, SIG_IGN); /* i realize that these 2 statements */ signal(SIGHUP, SIG_IGN); /* could follow the if */ #endif if (!signum) { #ifndef LINT signal(SIGINT, trap); signal(SIGHUP, trap); #endif return; } fini(EINTERRUPT); exit(1); } /* ** fini() - misc. things to be done before termination ** - print status at termination of processes */ void fini (status) reg int status; { reg int i; auto process *spcs[MAX_USERS]; if (ON(VISUAL)) { msg("Hit return to continue"); getchar(); if (ON(STATUS)) statfini(); vfini(); } printf("Halted: %s\n", diedstr(status)); for (i=0; i < jobcnt; i++) { if (!pcs[i].pdied) pcs[i].picnt = cycle; spcs[i] = &(pcs[i]); } qsort(spcs, jobcnt, sizeof(spcs[0]), pcscompar); printf("%-20s\t#Inst\tPC\tReason for termination\n", "Process"); for (i=0; i<jobcnt; i++) printf("%-20s\t%5d\t%4d\t%s\n", spcs[i]->pname, spcs[i]->picnt, spcs[i]->pc, diedstr(spcs[i]->pdied)); } /* ** pcscompar() - compare function used by qsort */ int pcscompar (p1, p2) reg process **p1, **p2; { return((*p2)->picnt - (*p1)->picnt); } /* ** diedstr() - return a string describing the reason for termination */ char *diedstr (status) reg int status; { switch (status) { when EALIVE: return("Still alive"); when ECYCLE: return("Cycle limit exceeded"); when EWIN: return("Winner found"); when EILLINST: return("Bad instruction"); when EBADMODE: return("Bad addressing mode"); when EINTERRUPT: return("Interrupted"); otherwise: return("Unknown reason"); } /*NOTREACHED*/ } /* ** get_start() - get a starting location for process ** - starting locations on page boundaries ** - return negative on error ** ** Assumption: ** If start location can't be found, then there are too many jobs. */ int get_start () { reg int i; reg int start; start = rand() % MAX_MEM; start -= start % PAGESIZE; for (i = 0; i < MAX_USERS; i++) { if (!collision(start)) return(start); start = sum(start, (min_sep * PAGESIZE)); } return(-1); } /* ** collision() - return TRUE if address is taken, else FALSE */ int collision (addr) reg int addr; { reg int i; auto int ll, /* lower limit to range */ ul; /* upper limit to range */ for (i=0; i<jobcnt; i++) { ll = sum(pcs[i].pc, -min_sep); ul = sum(sum(pcs[i].pc, pcs[i].psize), min_sep); if (pcs[i].pc >= ul || pcs[i].pc <= ll) { /* wrapped around memory */ if (addr <= ul || addr >= ll) return(TRUE); continue; } if (addr >= ll && addr <= ul) return(TRUE); } return(FALSE); } /* ** load() - load the player ** - return the size of the player (in instructions), 0 on error */ int load (fname, start) char *fname; reg int start; { reg int i, status; reg FILE *fp; if (!(fp = fopen(fname, "r"))) { perror(fname); return(0); } for (i=start; (status=fread(&(memory[i]),sizeof(memory[i]),1,fp)) == 1; i++) continue; fclose(fp); if (status < 0) return(0); return(i - start); } /* ** zeromem() - set all memory locations to zero */ void zeromem () { reg int i; for (i=0; i<MAX_MEM; i++) memory[i].op = memory[i].val = 0; } /* ** randomize() - randomize the random number generator */ static void randomize (seed) reg int seed; { extern long getpid(); extern long time(); if (seed) { srand(seed); return; } srand(seed = (int) ((time(0) + getpid()) & 0x0000ffffL)); printf("seed: %d\n", seed); } /* ** usage() - print a usage message and exit */ static void usage () { fprintf(stderr, "Usage: %s [-dilpv] [-rn] [-sn] [-cn] file ...\n", argv0); exit(1); } SHAR_EOF if test -f 'movmem.c' then echo shar: over-writing existing file "'movmem.c'" fi cat << \SHAR_EOF > 'movmem.c' /* ** movmem.c - ** static char rcsid[] = "$Header: movmem.c,v 7.0 85/12/28 14:35:55 ccohesh Dist $"; ** */ #include "cw.h" /* ** movmem() - move contents of one location in `memory' to another */ void movmem (m1, m2) reg memword *m1, *m2; { m1->op = m2->op; m1->moda = m2->moda; m1->modb = m2->modb; m1->arga = m2->arga; m1->argb = m2->argb; } SHAR_EOF if test -f 'msg.c' then echo shar: over-writing existing file "'msg.c'" fi cat << \SHAR_EOF > 'msg.c' /* ** msg.c - code dealing with the printing of messages ** ** Routines: ** msginit() initialize the window ** msgfini() de-initialize the window ** msg(fmt, args) write message to window ** msgclear() clear the message window ** ** [cw by Peter Costantinidis, Jr. @ University of California at Davis] ** static char rcsid[] = "$Header: msg.c,v 7.0 85/12/28 14:36:01 ccohesh Dist $"; ** */ #include <curses.h> #include <ctype.h> #include "cw.h" static WINDOW *msgwin; /* status window for msg's */ extern void doadd(); /* ** msginit() - initialize the message window ** - return non-zero on error */ int msginit () { if (!(msgwin = subwin(stdscr, MSGLINES, MSGCOLS, MSGYBEGIN, MSGXBEGIN))) { fprintf(stderr, "%s: message screen initialization error\n", argv0); return(TRUE); } wclear(msgwin); scrollok(msgwin, TRUE); return(FALSE); } /* ** msgfini() - re-initialize the message window */ void msgfini () { wclear(msgwin); delwin(msgwin); } static char msgbuf[BUFSIZ]; /* ** msg() - display message in message window using printf() like ** function */ /*VARARGS1*/ void msg (fmt, args) char *fmt; int args; { /* ** if the string is "", just clear the line */ if (*fmt == '\0') { wclear(msgwin); wrefresh(msgwin); return; } /* ** otherwise print the message and flush it out */ doadd(fmt, &args); waddch(msgwin, '\n'); waddstr(msgwin, msgbuf); wrefresh(msgwin); } static void doadd (fmt, args) char **fmt; int ***args; { static FILE junk; /* ** Do the printf into buf */ #ifdef _IOSTRG junk._flag = _IOWRT + _IOSTRG; junk._ptr = &msgbuf[0]; #else junk._flag = _IOWRT; junk._file = _NFILE; junk._ptr = (unsigned char *) &msgbuf[0]; #endif junk._cnt = 32767; _doprnt(fmt, args, &junk); putc('\0', &junk); } /* ** punctrl() - print a readable version of a certain character ** ** Note: Due to the inconsistent availability of a function to perform ** this, my own version has been built in and used in place of ** any pre-existing function. I believe that this particular ** version suts down on data space considerably from the versions ** I have found on the Berkley systems. */ char *punctrl (ch) char ch; { static char *str = "^ "; ch &= 0177; if (ch >= ' ' && ch <= '~') { static char *str1 = " "; *str1 = ch; return(str1); } if (ch == CINTR) return("^?"); *(str+1) = ch + '@'; return(str); } SHAR_EOF if test -f 'print.c' then echo shar: over-writing existing file "'print.c'" fi cat << \SHAR_EOF > 'print.c' /* ** print.c - various printing routines ** ** [cw by Peter Costantinidis, Jr. @ University of California at Davis] ** static char rcsid[] = "$Header: print.c,v 7.0 85/12/28 14:36:14 ccohesh Dist $"; ** */ #include <stdio.h> #include "cw.h" /* ** printit() - print the given instruction ** - return non-zero on error */ int printit (fp, i) FILE *fp; reg memword *i; { reg char *inst, *fmt; auto char adda, addb; static char *fmt1 = "%3.3s\t\t%c%d\n", *fmt2 = "%3.3s\t%c%d\t%c%d\n"; switch (i->op) { when DAT: inst = SDAT, fmt = fmt1; when MOV: inst = SMOV, fmt = fmt2; when ADD: inst = SADD, fmt = fmt2; when SUB: inst = SSUB, fmt = fmt2; when JMP: inst = SJMP, fmt = fmt1; when JMZ: inst = SJMZ, fmt = fmt2; when DJZ: inst = SDJZ, fmt = fmt2; when CMP: inst = SCMP, fmt = fmt2; when MUL: inst = SMUL, fmt = fmt2; when DIV: inst = SDIV, fmt = fmt2; when RND: inst = SRND, fmt = fmt1; otherwise: return(TRUE); } switch (i->moda) { when IMM: adda = CIMM; when REL: adda = CREL; when IND: adda = CIND; otherwise: adda = '?'; } switch (i->modb) { when IMM: addb = CIMM; when REL: addb = CREL; when IND: addb = CIND; otherwise: addb = '?'; } if (fmt == fmt1) fprintf(fp, fmt, inst, addb, rel_fix( i->argb ) ); /* budd */ else fprintf(fp, fmt, inst, adda, rel_fix( i->arga ), /* budd */ addb, rel_fix( i->argb )); /* budd */ return(FALSE); } rel_fix( i ) /* make output relative - budd */ int i; { if( i > MAX_MEM/2 ) /* addr over half of memory away? */ return( i - MAX_MEM ); /* yes, display as behind us */ else return( i ); } SHAR_EOF if test -f 'random.rc' then echo shar: over-writing existing file "'random.rc'" fi cat << \SHAR_EOF > 'random.rc' / random.rc - drop bombs in random places (slightly suicidal) $START: rnd $WHERE / set bomber address mov 0 @$WHERE / drop bomb jmp $START / let's do it again! $WHERE: dat 0 / where to drop the bomb SHAR_EOF if test -f 'rcasm.l' then echo shar: over-writing existing file "'rcasm.l'" fi cat << \SHAR_EOF > 'rcasm.l' /* ** lexical analyzer for input to Redcode Assembler ** ** [cw by Peter Costantinidis, Jr. @ University of California at Davis] ** static char rcsid[] = "$Header: rcasm.l,v 7.0 85/12/28 14:37:16 ccohesh Dist $"; ** */ /* definitions */ I -?[0-9]+ C \/.*$ W [" "\t]+ L "$"[a-zA-Z0-9]+ %% {C} return(COMMENT); dat|DAT { opcode=DAT; orc=1; return(OPCODE); } mov|MOV { opcode=MOV; orc=2; return(OPCODE); } add|ADD { opcode=ADD; orc=2; return(OPCODE); } sub|SUB { opcode=SUB; orc=2; return(OPCODE); } jmp|JMP { opcode=JMP; orc=1; return(OPCODE); } jmz|JMZ { opcode=JMZ; orc=2; return(OPCODE); } djz|DJZ { opcode=DJZ; orc=2; return(OPCODE); } cmp|CMP { opcode=CMP; orc=2; return(OPCODE); } mul|MUL { opcode=MUL; orc=2; return(OPCODE); } div|DIV { opcode=DIV; orc=2; return(OPCODE); } rnd|RND { opcode=RND; orc=1; return(OPCODE); } "#" return(OIMM); "@" return(OIND); "\n" return(NL); {W} ; ^{L}":" { static char buf[LABEL_LEN+1]; auto int len = min(yyleng-2, LABEL_LEN); strncpy(buf, &(yytext[1]), len); buf[len] = '\0'; dlabel = &(buf[0]); return(DLABEL); } {L} { static char bufs[2][LABEL_LEN+1]; auto int len = min(yyleng+1, LABEL_LEN); auto char **ptr; if (orc == 1) ptr = &blabel; else ptr = (toggle ? &blabel : &alabel); strncpy(bufs[toggle], &(yytext[1]), len); bufs[toggle][len] = '\0'; *ptr = bufs[toggle]; toggle = (toggle ? 0 : 1); return(LABEL); } {I} { extern int yylval; if (sscanf(yytext, "%d", &yylval) != 1) return(ERROR); yylval = sum(yylval, 0); toggle = (toggle ? 0 : 1); return(INTEGER); } . { fprintf(stderr, "%s: unrecognized character in lex: %o\n", argv0, yytext[0]); return(ERROR); } %% SHAR_EOF if test -f 'rcasm.l.old' then echo shar: over-writing existing file "'rcasm.l.old'" fi cat << \SHAR_EOF > 'rcasm.l.old' /* ** lexical analyzer for input to Redcode Assembler ** ** [cw by Peter Costantinidis, Jr. @ University of California at Davis] ** static char rcsid[] = "$Header: rcasm.l,v 7.0 85/12/28 14:37:16 ccohesh Dist $"; ** */ /* definitions */ I -?[0-9]+ C \/.*$ W [" "\t]+ L "$"[a-zA-Z0-9]+ %% {C} return(COMMENT); dat|DAT return(opcode=DAT, orc=1, OPCODE); mov|MOV return(opcode=MOV, orc=2, OPCODE); add|ADD return(opcode=ADD, orc=2, OPCODE); sub|SUB return(opcode=SUB, orc=2, OPCODE); jmp|JMP return(opcode=JMP, orc=1, OPCODE); jmz|JMZ return(opcode=JMZ, orc=2, OPCODE); djz|DJZ return(opcode=DJZ, orc=2, OPCODE); cmp|CMP return(opcode=CMP, orc=2, OPCODE); mul|MUL return(opcode=MUL, orc=2, OPCODE); div|DIV return(opcode=DIV, orc=2, OPCODE); rnd|RND return(opcode=RND, orc=1, OPCODE); "#" return(OIMM); "@" return(OIND); "\n" return(NL); {W} ; ^{L}":" { static char buf[LABEL_LEN+1]; auto int len = min(yyleng-2, LABEL_LEN); strncpy(buf, &(yytext[1]), len); buf[len] = '\0'; dlabel = &(buf[0]); return(DLABEL); } {L} { static char bufs[2][LABEL_LEN+1]; auto int len = min(yyleng+1, LABEL_LEN); auto char **ptr; if (orc == 1) ptr = &blabel; else ptr = (toggle ? &blabel : &alabel); strncpy(bufs[toggle], &(yytext[1]), len); bufs[toggle][len] = '\0'; *ptr = bufs[toggle]; toggle = (toggle ? 0 : 1); return(LABEL); } {I} { extern int yylval; if (sscanf(yytext, "%d", &yylval) != 1) return(ERROR); yylval = sum(yylval, 0); toggle = (toggle ? 0 : 1); return(INTEGER); } . { fprintf(stderr, "%s: unrecognized character in lex: %o\n", argv0, yytext[0]); return(ERROR); } %% SHAR_EOF if test -f 'rcasm.y' then echo shar: over-writing existing file "'rcasm.y'" fi cat << \SHAR_EOF > 'rcasm.y' /* ** grammar for the input to the Redcode Assembler ** ** [cw by Peter Costantinidis, Jr. @ University of California at Davis] ** static char rcsid[] = "$Header: rcasm.y,v 7.0 85/12/28 14:37:04 ccohesh Dist $"; ** */ /* instructions */ %{ #include <stdio.h> #include "cw.h" typedef struct /* simple single purpose symbol table */ { int sym_abs; /* absolute address of symbol */ char *sym_nam; /* symbols name */ } symtab; memword inst; /* current instruction */ memword memory[JMAX_LEN]; symtab symbols[MAX_LABELS]; /* symbol table */ symtab *unres[JMAX_LEN]; /* list of unresolved references */ uns opcode; /* set in lexical analyzer */ int icnt = 0; /* instruction count */ int lcnt = 1; /* line count */ int ocnt = 0; /* # of operands for current instruction */ int toggle = 0; /* for multi-arg inst.'s indicates which arg */ int orc; /* required # of operands for current inst. */ char *dlabel, *alabel, *blabel;/* set in lexical analyzer */ extern void yyerror(); %} /* operand tokens */ %token OIMM /* number is operand (#) */ %token OREL /* number specifies offset from current instruction ( ) */ %token OIND /* number specifies offset from current instruction (@) */ /* to location where relative address of operand is found */ %token OPCODE %token INTEGER /* the operands */ %token COMMENT /* a comment */ %token ERROR /* error in lex */ %token NL /* new line */ %token DLABEL /* defining a label */ %token LABEL /* a label being used */ %start program %% /* beginning of rules section */ program : /* empty */ | program line | program error NL { toggle = 0; lcnt++; yyerrok; } ; line : comment NL { lcnt++; } | label statement comment NL { inst.op = $2; lcnt++; toggle = 0; /* a hack for labels */ if (icnt > JMAX_LEN) { static int once = FALSE; if (!once) { once = TRUE; fprintf(stderr, "Maximum instruction limit of %d exceeded\n", JMAX_LEN); fprintf(stderr, "Will continue processing...\n"); } } movmem(&(memory[icnt++]), &inst); } ; label : | DLABEL { if (addsym(dlabel)) YYERROR; } ; comment : | COMMENT ; statement: OPCODE arga argb { if (orc != 2) { yyerror("bad argument count"); YYERROR; } if ((opcode == MOV && $3 == IMM) || (opcode == ADD && $3 == IMM) || (opcode == SUB && $3 == IMM) || (opcode == JMZ && $3 == IMM) || (opcode == DJZ && $3 == IMM) || (opcode == MUL && $3 == IMM) || (opcode == DIV && $3 == IMM)) { yyerror("non-sensicle mode for operand"); YYERROR; } $$ = opcode; } | OPCODE argb { if (orc != 1) { yyerror("bad argument count"); YYERROR; } if ((opcode == JMP && $2 == IMM) || (opcode == RND && $2 == IMM) || (opcode == DAT && $2 != REL)) { yyerror("non-sensicle mode for operand"); YYERROR; } $$ = opcode; } ; arga : addr INTEGER /* returns addr */ { $$ = $1; inst.moda = $1; inst.arga = $2; } | addr LABEL { $$ = $1; inst.moda = $1; inst.arga = getsymval(alabel, 0); } ; argb : addr INTEGER /* returns addr */ { $$ = $1; inst.modb = $1; inst.argb = $2; } | addr LABEL { $$ = $1; inst.modb = $1; inst.argb = getsymval(blabel, 1); } ; addr: /* no operand (relative addressing mode) */ { $$=REL; } | OIMM { $$=IMM; } | OIND { $$=IND; } ; %% char *argv0; extern void fatal(), init(); /* ** main() - the main program */ void main (argc, argv) reg int argc; reg char **argv; { auto char buf[BUFSIZ]; reg char *ptr; auto char *ifname, *ofname; auto int error = 0; argv0 = *argv++, argc--; ofname = RC_OUT; if (argc < 1) usage(); ifname = *argv++, argc--; if (argc > 1) usage(); if (argc) ofname = *argv; if (!freopen(ptr = ifname, "r", stdin) || !freopen(ptr = ofname, "w", stdout)) { perror(ptr); exit(1); } init(); error = yyparse(); fclose(stdin); if (error) fprintf(stderr, "%s: yyparse() error\n", argv0); if (error || fini()) { fclose(stdout); unlink(ofname); exit(1); } exit(0); } /* ** fini() - resolve any unresolved symbols ** - write instructions */ int fini () { reg int i; reg symtab **us = unres; auto int error = FALSE; for (us = unres; *us; us++) { reg symtab *s; auto int inum = abs((*us)->sym_abs)-1; extern symtab *getsym(); if (!(s = getsym((*us)->sym_nam)) || s->sym_abs < 0) { fprintf(stderr, "Inst. %d: label \"%s\" not defined\n", inum, (*us)->sym_nam); error++; continue; } /* fprintf(stderr, "Us inum: %d, \"%s\", %d\n", inum, (*us)->sym_nam, (*us)->sym_abs); */ if ((*us)->sym_abs < 0) memory[inum].argb = s->sym_abs - inum; else memory[inum].arga = s->sym_abs - inum; } if (error) { fprintf(stderr, "%d unresolved labels\n", error); fprintf(stderr, "%s: object file not created\n", argv0); return(TRUE); } for (i=0; i<icnt; i++) if (fwrite(&(memory[i]), sizeof(memory[i]), 1, stdout) != 1) { fprintf(stderr, "%s: write error to output file\n", argv0); perror(argv0); return(TRUE); } return(FALSE); } /* ** init() - perform various initializations */ void init () { reg int i; for (i=0; i<MAX_LABELS; i++) symbols[i].sym_nam = (char *) 0; for (i=0; i<JMAX_LEN; i++) unres[i] = (symtab *) NULL; } /* ** usage() - print a usage message and exit */ void usage () { fprintf(stderr, "Usage: %s infile [outfile]\n", argv0); exit(1); } /* ** yyerror() - yacc error routine */ void yyerror (msg) reg char *msg; { fprintf(stderr, "%s: error on line %d (%s)\n", argv0, lcnt, msg); } static int sym_cnt = 0; /* number of symbols in table */ extern symtab *_addsym(), *addunres(), *getsym(); /* ** getsymval() - return the value of the specified symbol relative to ** the current instruction ** - if symbol is undefined: ** add it to symtab w/o a value ** mark this instruction as having an unresolved symbol ** return 0 ** - if which==0, then arga, else argb */ int getsymval (sname, which) reg char *sname; reg int which; { reg symtab *s; auto int len; if (s = getsym(sname)) { if (s->sym_abs >= 0) return(s->sym_abs - icnt); } else s = _addsym(sname); s = addunres(s->sym_nam); s->sym_abs += 1; /* must be >0 */ if (which) s->sym_abs *= -1; /* negative for argb */ return(0); } /* ** addunres() - add a symbol to the unresolved list */ symtab *addunres (sname) reg char *sname; { static int index = 0; reg symtab **s = &(unres[index++]); if (index >= JMAX_LEN) fatal("Symbols used to often"); if (!(*s = (symtab *) malloc(sizeof(symtab)))) fatal("memory allocation failure"); (*s)->sym_nam = sname; (*s)->sym_abs = icnt; return(*s); } /* ** addsym() - add a symbol to the symbols[] list */ int addsym (sname) reg char *sname; { reg symtab *s; auto int len; if ((s = getsym(sname)) && s->sym_abs >= 0) { fprintf(stderr, "label \"%s\" multiply defined\n", sname); return(TRUE); } if (s) { /* previously used symbol is declared */ s->sym_abs = icnt; return(FALSE); } s = _addsym(sname); s->sym_abs = icnt; return(FALSE); } /* ** _addsym() - slightly lower lever function, used by both addsym() ** and getsymval() */ symtab *_addsym (sname) reg char *sname; { reg symtab *s = &(symbols[sym_cnt++]); reg int len; if (!(s->sym_nam = (char *) malloc(len=(strlen(sname)+1)))) { fprintf(stderr, "%s: can't malloc %d bytes\n", argv0, len); fatal("memory allocation failure"); } strcpy(s->sym_nam, sname); s->sym_abs = -1; return(s); } /* ** getsym() - return a pointer to the specified symbol in the symbol table */ symtab *getsym (sname) reg char *sname; { reg int i; for (i=0; i<sym_cnt; i++) if (!strcmp(sname, symbols[i].sym_nam)) return(&(symbols[i])); return((symtab *) NULL); } /* ** fatal() - print an error message and exit */ void fatal (mesg) reg char *mesg; { fprintf(stderr, "%s: FATAL error: %s\n", argv0); exit(1); } #include "rcasm.h" /* the lexical analyzer */ SHAR_EOF if test -f 'scheduler.c' then echo shar: over-writing existing file "'scheduler.c'" fi cat << \SHAR_EOF > 'scheduler.c' /* ** scheduler.c - routines dealing with the running of the jobs ** ** [cw by Peter Costantinidis, Jr. @ University of California at Davis] ** static char rcsid[] = "$Header: scheduler.c,v 7.0 85/12/28 14:36:26 ccohesh Dist $"; ** */ #include <stdio.h> #include <setjmp.h> #include "cw.h" static int _pc; /* current pc */ static jmp_buf haltit; extern void halt(), run(); extern memword *getoperand(); /* ** scheduler() - run the processes ** - very simple algorithm to determine what job is scheduled next: ** jobs are scheduled by thier order in the process table ** - each job gets to execute one instruction during its scheduled ** period */ int scheduler (pcs) reg process *pcs; { reg int flag; if (ON(VISUAL)) return(vscheduler(pcs)); for (cycle=0; jobsleft > 1 && cycle < max_cyc; cycle++) { reg process *j; if (ON(PASSNUM) && (!(cycle % PASSFREQ) || ON(PINST))) printf("Pass #%04d\t", cycle); if (!ON(PINST) && ON(PASSNUM) && (!(cycle % PASSFREQ) || ON(PINST))) putchar('\r'), fflush(stdout); for (flag=0, j=pcs; j < (pcs+jobcnt); j++, flag++) { if (ON(PINST) && ON(PASSNUM) && flag && (!(cycle % PASSFREQ) || ON(PINST))) printf("\t\t"); if (!HALTED(j)) run(j); } } if (cycle >= max_cyc) return(ECYCLE); return(EWIN); } /* ** vscheduler() - the scheduler used for visual display mode */ int vscheduler (pcs) reg process *pcs; { for (cycle=0; jobsleft > 1 && cycle < max_cyc; cycle++) { reg process *j; for (j=pcs; j < (pcs+jobcnt); j++) if (!HALTED(j)) run(j); vupdate(pcs); if (ON(STATUS) && !(cycle % PASSFREQ) && ON(PASSNUM)) vstatus(); } if (cycle >= max_cyc) return(ECYCLE); return(EWIN); } /* ** run() - execute one instruction of the given job */ static void run (j) reg process *j; { reg memword *w; reg int status; /* fetch pc (incremented at end of function or where appropriate) */ PC = j->pc; /* fetch instruction */ w = &(memory[j->pc]); /* remember this for halting processes */ if (status = SETJMP(haltit)) { halt(j, status); return; } if (ON(PINST)) { printf("PC: %4d\t", PC); if (printit(stdout, w)) fprintf(stderr, "%s: printit() error\n", argv0); } switch (w->op) { auto int tmp; #define A w->moda, w->arga #define B w->modb, w->argb /* ** when modifying memory locations through arithmetic operations ** make sure the opcode gets reset */ #define COREA tmp=getaddr(w->moda, w->arga),memory[tmp].op=DAT,memory[tmp].val #define COREB tmp=getaddr(w->modb, w->argb),memory[tmp].op=DAT,memory[tmp].val when MOV:/* move A into location B */ movmem(j->plstmem=(&(memory[getaddr(B)])), getoperand(A)); when ADD:/* add A to contents of B, results in B */ COREB = sum((int) (getoperand(A))->val,(int) (getoperand(B))->val); when MUL: { reg int temp = (int) (getoperand(B))->val; temp *= (int) (getoperand(A))->val; COREB = sum(temp, 0); } when DIV: { reg int temp = (int) (getoperand(B))->val; temp /= (int) (getoperand(A))->val; COREB = sum(temp, 0); } when SUB:/* subtract A from contents of B, results in B */ COREB = sum((int) -(getoperand(A))->val,(int) (getoperand(B))->val); when JMP:/* jump to B */ j->pc = getaddr(B); return; when JMZ:/* if A == 0 then jump to B, otherwise continue */ if (getoperand(A)->val == 0) { j->pc = getaddr(B); return; } when DJZ:/* --A; if A == 0 then jump to B */ COREA = sum((int) getoperand(A)->val, -1); if (COREA == 0) { j->pc = getaddr(B); return; } when CMP:/* compare A with B; if != then skip next inst. */ if (getoperand(A)->val != getoperand(B)->val) { j->pc = sum(j->pc, 2); return; } when RND:/* into A a random number between 0 and MAX_MEM */ COREB = sum((int) rand(), 0); otherwise: halt(j, EILLINST); #undef A #undef B #undef COREA #undef COREB } if (!HALTED(j)) j->pc = sum(j->pc, 1); /* increment pc */ } /* ** getoperand() - return the operand ** - since a pointer to static data is returned, care is ** taken to insure that this static data isn't corrupted ** due to two `simultaneous' calls. */ static memword *getoperand (m, a) reg uns m, a; { static memword mw1, mw2, *mw; mw = (mw == &mw1) ? &mw2 : &mw1; switch (m) { case IMM: mw->op = 0; mw->val = a; return(mw); case REL: return(&(memory[sum(PC, (int) a)])); case IND: return(&(memory[getaddr(m,a)])); default: LONGJMP(haltit, EBADMODE); } /*NOTREACHED*/ } /* ** getaddr() - return the address */ static int getaddr (m, a) reg uns m, a; { switch (m) { case REL: return(sum((int) PC, (int) a)); case IND: { reg int tmp; tmp = sum(PC, (int) a); return(sum(tmp, (int) memory[tmp].val)); } case IMM: default: LONGJMP(haltit, EBADMODE); } /*NOTREACHED*/ } /* ** halt() - halt the specified process */ static void halt (j, reason) reg process *j; reg int reason; { #ifdef DEBUG fprintf(stderr, "%s: process \"%s\" halted\n", argv0, j->pname); #endif j->pdied = reason; j->picnt = cycle; jobsleft--; if (ON(VISUAL) && ON(STATUS)) vstajob(j); } SHAR_EOF if test -f 'stomper.rc' then echo shar: over-writing existing file "'stomper.rc'" fi cat << \SHAR_EOF > 'stomper.rc' / / stomper.rc - son of dwarf and gemini (he's a mover and he's aggressive) / jmp $START /jump to start of program $SRC: dat 0 /pointer to source address $DST: dat 191 /pointer to destination address $START: mov @$SRC @$DST /copy source to destination cmp $SRC #13 /if all 10 lines have been copied... jmp $DONE /...then leave the loop add #1 $SRC /otherwise, increment the source address add #1 $DST /...and the destination address add #8 $BOMB /increment bomber address mov #0 @$BOMB /drop bomb jmp $START /...and return to the loop $DONE: mov #4 @$DST /reset bomber address mov #191 182 /restore the starting destination address jmp 182 /jump to the new copy $BOMB: dat 4 SHAR_EOF if test -f 'sum.c' then echo shar: over-writing existing file "'sum.c'" fi cat << \SHAR_EOF > 'sum.c' /* ** sum.c - add two numbers, wrapping if sum is out-of-bounds ** ** [cw by Peter Costantinidis, Jr. @ University of California at Davis] ** static char rcsid[] = "$Header: sum.c,v 7.0 85/12/28 14:36:36 ccohesh Dist $"; ** */ #include "cw.h" /* ** sum() - sum two integers w/ memory wrapping */ int sum (x, y) reg int x, y; { reg int tot = x + y; if (tot < 0) return(sum(MAX_MEM + tot, 0)); if (tot >= MAX_MEM) return(tot % MAX_MEM); return(tot); } SHAR_EOF if test -f 'unrc.c' then echo shar: over-writing existing file "'unrc.c'" fi cat << \SHAR_EOF > 'unrc.c' /* ** unrc.c - disassemble rc binaries ** ** [cw by Peter Costantinidis, Jr. @ University of California at Davis] ** static char rcsid[] = "$Header: unrc.c,v 7.0 85/12/28 14:36:48 ccohesh Dist $"; ** */ #include <stdio.h> #include "cw.h" char *argv0; main (argc, argv) reg int argc; reg char **argv; { auto memword i; argv0 = *argv++, argc--; if (argc == 0) *argv = RC_OUT; else if (argc != 1) usage(); if (!freopen(*argv, "r", stdin)) { perror(*argv); exit(1); } while (fread((char *) &i, sizeof(i), 1, stdin) == 1) unrc(&i); fclose(stdin); } /* ** unrc() - unassemble the given instruction */ unrc (i) reg memword *i; { reg int incnt; static int icnt = 0; icnt++; switch (i->op) { when DAT: case JMP: case RND: incnt = 1; when MOV: case ADD: case SUB: case JMZ: case DJZ: case CMP: case MUL: case DIV: incnt = 2; otherwise: fprintf(stderr, "Inst. %d: bad opcode: %d\n", icnt, i->op); return; } switch (i->modb) { case IMM: case REL: case IND: otherwise: fprintf(stderr, "Inst. %d: bad address mode for B\n", icnt); return; } if (incnt == 1) { if (printit(stdout, i)) fprintf(stderr, "Inst. %d: printit() problem\n", icnt); return; } switch (i->moda) { case IMM: case REL: case IND: otherwise: fprintf(stderr, "Inst. %d: bad address mode for A\n", icnt); return; } if (printit(stdout, i)) fprintf(stderr, "Inst. %d: printit() problem\n", icnt); } /* ** usage() - print a usage message and exit */ void usage () { fprintf(stderr, "Usage: %s file\n", argv0); exit(1); } SHAR_EOF if test -f 'vdisplay.c' then echo shar: over-writing existing file "'vdisplay.c'" fi cat << \SHAR_EOF > 'vdisplay.c' /* ** vdisplay.c - routines dealing with the visual display of the ** Corewar game ** ** [cw by Peter Costantinidis, Jr. @ University of California at Davis] ** static char rcsid[] = "$Header: vdisplay.c,v 7.0 85/12/28 14:36:39 ccohesh Dist $"; ** */ #include <curses.h> #include <ctype.h> #include "cw.h" /* ** Strategy: ** ** 1. Fill the screen with a rectangle of characters (MEMPTY). ** Let each character represent 10 memory locations. ** Since MAX_MEM is 10,000 (and I am afraid this value is ** going to be rather hard coded into the display routines) ** this will have to be a 50 column by 20 row box. ** 2. Place an uppercase letter in the location corresponding to ** the value of the job's PC. If more than one job occupies the ** same location, then place a digit representing the number of ** jobs. ** 3. Place a lowercase letter at the square corresponding to the ** memory location that the job is modifying. If more than one ** job is modifying the same memory section, place MSHARE there. ** 4. If a job is modifying a memsect that another job is modifying, ** place a MHIT. ** ** Therefore, we need routines to do the following: ** ** initialize window ** fill with MEMPTY's ** update screen wrt PC values and delta mem locs */ #define BOXS(p) (p/NUMMEM) #define BOXX(p) (BOXS(p) % MCOLS) #define BOXY(p) (BOXS(p) / MCOLS) static WINDOW *memwin; extern void clearbox(), membox(); /* ** vupdate() - update the memory display */ int vupdate (ps) reg process *ps; { reg process *p; for (p = ps; (p - ps) < jobcnt; p++) { /* update plstmem's */ auto int addr = (p->plstmem - &(memory[0])); auto int y = BOXY(addr), /* hides earlier def. */ x = BOXX(addr); /* hides earlier def. */ auto char pch = (char) p->pid + 'a'; reg char ch; if (!p->plstmem || p->pdied) continue; if ((addr/PAGESIZE) == (p->pc/PAGESIZE)) continue; /* writing to same mem page */ if ((ch = mvwinch(memwin, y, x)) == MEMPTY) waddch(memwin, pch); else if (islower(ch)) waddch(memwin, MSHARE); else msg("Unknown character in membox (%s) @ (%d,%d)", punctrl(ch), y, x); } for (p = ps; (p - ps) < jobcnt; p++) { /* upate pc's */ auto int y = BOXY(p->pc), /* hides earlier def. */ x = BOXX(p->pc); /* hides earlier def. */ auto char pch = (char) p->pid + 'A'; reg char ch = mvwinch(memwin, y, x); if (p->pdied || ch == MFULL || ch == MHIT) continue; if (ch == MEMPTY) waddch(memwin, pch); else if (isupper(ch)) waddch(memwin, '2'); else if (isdigit(ch)) waddch(memwin, (ch<'9') ? (ch + (char) 1) : MFULL); else if (ch == MSHARE) waddch(memwin, MHIT); else if (islower(ch)) { if (ch == tolower(pch)) waddch(memwin, pch); else waddch(memwin, MHIT); } else msg("unknown character in membox (%s) @ (%d,%d)", punctrl(ch), y, x); } wrefresh(memwin); for (p = ps; (p - ps) < jobcnt; p++) { /* upate pc's */ auto int addr = (p->plstmem - &(memory[0])); if (p->pdied) continue; mvwaddch(memwin, BOXY(p->pc), BOXX(p->pc), MEMPTY); if (!p->plstmem) continue; mvwaddch(memwin, BOXY(addr), BOXX(addr), MEMPTY); } } /* ** vinit() - perform curses initializations ** - initialize memory window ** - return non-zero on error */ int vinit () { if (initscr() == ERR) { fprintf(stderr, "%s: screen initialization error\n", argv0); perror(argv0); return(TRUE); } if (LINES < MIN_LINES || COLS < MIN_COLS) { fprintf(stderr, "%s: screen must be at least %d by %d\n", argv0, MIN_LINES, MIN_COLS); return(TRUE); } if (!(memwin = subwin(stdscr, MLINES, MCOLS, MYBEGIN, MXBEGIN))) { fprintf(stderr, "%s: can't create memory-window\n", argv0); return(TRUE); } if (msginit()) return(TRUE); membox(); clearbox(); refresh(); crmode(); noecho(); return(FALSE); } /* ** vfini() - perform screen shutdown actions */ void vfini () { msgfini(); clear(); refresh(); delwin(memwin); endwin(); } /* ** clearbox() - fill the box with MEMPTY's */ static void clearbox () { reg int y, x; for (y=0; y<MLINES; y++) for (x=0; x<MCOLS; x++) mvwaddch(memwin, y, x, MEMPTY); } /* ** membox() - draw a box around the memory window */ static void membox () { reg int y, x; for (x = MXBEGIN-1, y = MYBEGIN-1; x < (MXBEGIN+MCOLS+1); x++) mvaddch(y, x, HORTBORDER), mvaddch(y+MLINES+1, x, HORTBORDER); for (y = MYBEGIN, x = MXBEGIN-1; y < (MYBEGIN+MLINES); y++) mvaddch(y, x, VERTBORDER), mvaddch(y, x+MCOLS+1, VERTBORDER); } SHAR_EOF if test -f 'vstatus.c' then echo shar: over-writing existing file "'vstatus.c'" fi cat << \SHAR_EOF > 'vstatus.c' /* ** vstatus.c - manage the status window ** ** [cw by Peter Costantinidis, Jr. @ University of California at Davis] ** static char rcsid[] = "$Header: vstatus.c,v 7.0 85/12/28 14:36:44 ccohesh Dist $"; ** */ #include <curses.h> #include "cw.h" static WINDOW *statwin; /* ** statinit() - initialize the status window */ int statinit (jobs) reg process *jobs; { reg int i; if (!(statwin = subwin(stdscr, SLINES, SCOLS, SYBEGIN, SXBEGIN))) { fprintf(stderr, "%s: status screen initialization error\n", argv0); return(TRUE); } wclear(statwin); scrollok(statwin, FALSE); for (i=0; i<jobcnt && i < SLINES; i++) vstajob(jobs++); if (ON(PASSNUM)) vstatus(); return(FALSE); } /* ** statfini() - de-initialize the status window */ void statfini () { wclear(statwin); delwin(statwin); } /* ** vstatus() - print the current cycle number and jobs left ** in the status window */ void vstatus () { wmove(statwin, SLINES-1, 0); wprintw(statwin, "Cycle: %04d Jobs: %2d", cycle, jobsleft); wrefresh(statwin); } /* ** vstajob() - update the entry for the given job in the status window */ void vstajob (j) reg process *j; { wmove(statwin, j->pid, 0); wprintw(statwin,"%c. \"%.10s\" %4d %s", 'A' + j->pid, j->pname, j->pc, diedstr(j->pdied)); wrefresh(statwin); } SHAR_EOF # End of shell archive exit 0