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