c60a-3ci@web-3f.berkeley.edu (An Existentialist) (01/21/89)
Here's a copy of the COREWARS programs. To extract, save to a file, delete this headers, and type: %sh < <filename> The MANIFEST file should have a listing of ALL the files included with this package. Na Choon Piaw c60a-3ci@wolf.berkeley.edu (soon to be changed) 301P, 2650 Durant, Berkeley, CA 94720. P.S. There is also a "bitmapped" display version that works ONLY for the SUN. You must have a SUN 3/50 or better and the pixrect library for it to work. Mail me for the source. ----------------------- cut here ------------------------- echo x - MANIFEST cat >MANIFEST <<'!E!O!F!' CoreWars public distribution package, by Na Choon Piaw. You should have the following files: Assembler: assem.h - assembler data structures assem.c - assembler function disassemble - disassembler lookup.c - does symbol matching amain.c - "main" for the assembler aoutput.c - output function for the assembler parse.c - parser for the assembler tokenize.c - tokenizer for the assembler MakeAss - Makefile for the assembler Interpreter: interp.h - interpreter data structures inst.c - implementation of simulator load.c - loader main.c - "main" for the interpreter output.c - output functions for the interpreter MakeInt - Makefile for the interpreter *.rc - redcode programs (sample) MANIFEST - this file README - documentation file To install, type: %make -f MakeAss %make -f MakeInt %assem *.rc Please send all bug reports and modifications as well as other interesting notes to: Na Choon Piaw c60a-3ci@web.berkeley.edu 301P, 2650 Durant, Berkeley, CA 94720. (to be changed later) Note: You are now a "registered user". Doesn't mean anything, means I've got a list of people to send updates to. !E!O!F! echo x - MakeAss cat >MakeAss <<'!E!O!F!' all: assem disassem assem: amain.o tokenize.o parse.o lookup.o aoutput.o assem.o cc amain.o tokenize.o parse.o assem.o lookup.o aoutput.o -o assem disassem: disassem.c assem.h cc -O disassem.c -o disassem main.o: amain.c assem.h cc -O -c amain.c -o main.o tokenize.o: tokenize.c assem.h cc -O -c tokenize.c -o tokenize.o parse.o: parse.c assem.h cc -O -c parse.c -o parse.o lookup.o: lookup.c assem.h cc -O -c lookup.c -o lookup.o output.o: aoutput.c assem.h cc -O -c aoutput.c -o aoutput.o assem.o: assem.c assem.h cc -O -c assem.c -o assem.o !E!O!F! echo x - MakeInt cat >MakeInt <<'!E!O!F!' CFLAGS = -DSMALL interp: main.o load.o output.o play.o inst.o cc -o interp main.o load.o output.o play.o inst.o -lcurses -ltermcap main.o: interp.h main.c MakeInt cc -c $(CFLAGS) main.c -o main.o load.o: interp.h load.c cc -c $(CFLAG) load.c -o load.o output.o: interp.h output.c MakeInt cc -c $(CFLAGS) output.c -o output.o play.o: play.c interp.h MakeInt cc -c $(CFLAGS) play.c -o play.o inst.o: inst.c interp.h cc -c $(FLAGS) inst.c -o inst.o !E!O!F! echo x - README cat >README <<'!E!O!F!' /* Copyrighted (C) 1989 by Na Choon Piaw. All rights reserved */ /* This program and documentation is Public Domain, and may be */ /* distributed and copied by everyone provided this header */ /* remains intact */ This is a new version of corewars I'm working on. It will feature ONLY 2 player games (I hate 3 or more players on corewars), some limited amounts of display (using curses) though that will be implemented only after the non-display functions work. And an independent, full featured assembler. The interpreter will load "binary" code only. Full featured -- 1 physical pass, 2 "in memory" passes. symbolic memory addresses, immediate, direct, and indirect addressing modes. COREWARS is a where the players each write an assembly language program that battle each other in the memory of a computer called MARS. (Memory Array Redcode Simulator) The game ends when (1) all the streams of execution on one side have died out, or (2) when the time limit is up. In (1) the winner is the side which still has surviving execution streams. In (2) the game is a draw. Once we are finished with implementing this game, maybe we can schedule a corewars tournament. My version of corewars implements (hopefully in a short while) the following instructions from World 7 --- The First Corewars Tournament (with some modifications) (Note: the first two articles have slightly differing definitions): INSTRUCTION MNEUMONIC CODE ARGUMENTS EXPLANATION Move mov 1 A B move contents of address A to address B Add add 2 A B add contents of address A to address B Subtract sub 3 A B subtract contents of address A from address B Jump jmp 4 B Transfer control to address A Jump if zero jmz 5 A B Transfer control to address A if contents of B are greater then 0 Jump if not 0 jmn 6 A B transfer control to address B if contents of B is != 0 Decrement jump djn 7 A B Subtract 1 from if not zero contents of address B and transfer control to address A if contents of address B is != 0 Compare cmp 8 A B compare contents of addresses A and B; if they are unequal, skip the next instruction. Split spl 9 B split execution into next instruction and the instruction at A Data statment dat 0 B A nonexecuatble statement; B is the data value. Addressing modes:- immediate mode: #argument direct mode: symbol indirect mode: @symbol Expected other differences - 1) When +/- are conducted to an address that contains other than a data instruction, parameter B is always modified (even in spl instructions). There is no way and add or sub instruction can change one type of instruction to another, so the CODE part of the table is really rather worthless. 2) The assembler will feature the "real" symbol. In other words, you do not have to convert all your symbols into numbers before feeding your program to the assembler. There will be a reserved symbol, though, called "start" and this will be where your code will start executing. All symbols are characterized by a ':' character at the end, e.g. "start:" 3) Separate assembly. In the interest of modularity and ease of debugging (for my code, of course, not for the redcode assembly program, so I still don't suggest writing 200 instruction redcode programs, even though the assembler permits it), I have decided to separate the assembler from the interpreter. The interpreter will have to be fed the preassembled programs, etc. in a special format. (produced by the assembler). 4) Will not implement stuff like the "<" or the ">". i.e., decrease stuff pointed to by operand, then get that address. 5) Randomized starting memory for the redcode programs. Make corewars more deterministic - predictable. Can be implemented later if demand arises. Other expected differences - BUGS!!! BUG REPORT SECTION:- assem/main.c - The program will not accept files with ".e" anywhere in the last portion of it (i.e., the extension) These files will be rejected. e.g. "mice.eecs" will be rejected tokenize.c - The program will not be able to handle comments without any delimiters between them and the code. e.g. "mov 0 1;;help" will be tokenized into: "mov" "0" "1;;help" which is not acceptable, since the later functions like lookup will not be able to handle it. play.c/main.c: - The BIG option (to fully bit map the memory array, doesn't work. I wonder why?) Note: A.K. Dewdney's THE ARMCHAIR UNIVERSE is available from Freeman (publisher). I highly recommend buying a copy and reading it. It's a whole lot of fun and teaches a lot of great programming techniques. It's moderately priced at around $13.25, and, in my opinion, worth every penny. Choon Piaw Assembler portion of corewars Usage: assem <file1> <file2> ..... All output files will have an additional extension ".e" for instance, if the input file was "help.rc" the ouput file will be "help.e" Assembler limits: 200 instructions 100 symbols 255 characters in a string Comments are indicated by a ; Assembler is not case sensitive. Remember that this does not conform to ALL the A.K. Dewdney standards in the implementation of OPCODES/PARAMETERS, but as long as you write code that does not depend on changing other's opcode, you should be all right. The instruction set is standard, however. BUGS: Any file starting with a .e extension is rejected automatically Any character is recognized as a symbol. Therefore, in mov 0 1;this is a comment 1;this will be interpreted as a symbol instead of a number with a comment following it. The proper form would be: mov 0 1 ;this is a comment Corewars interpreter - started 12/14/88 by Na Choon Piaw (The Existentialist) usage: interp cycles file1 file2 cycles -number of machine cycles file1, file2 -preassembled corewars programs Programmer's documentation for Redcode interpreter Goal: To provide a visual version of corewars that is fast, standard and portable. Modules 1. int loader(int position) - load up files into main memory to position. - setup the starting pcs 2. eval - input the memory element + a host of other info (including the list of streams) - each of the instructions will be handled by a separate subroutine that will be passed just sufficient info to carry it out. 3. control - responsible for keeping track of who's what and passing the correct instruction to the evaluator 4. Display - Display in a visual format (to be decided) what's going on in memory at that time. Data Structures Streams of execution are kept as circularly linked list, with split instructions adding to the linked list, and with trying to execute data instructions. All parameters will range from 0 to +8000. Excess will be trimmed off, negatives will be wrapped back around. Credit where credit is due: Case Larsen wrote and debugged the SUN graphics function interface2.c Adrain Ho wrote and debugged the loader load.c I wrote and debugged the rest. !E!O!F! echo x - assem.h cat >assem.h <<'!E!O!F!' /* Copyrighted (C) 1989 by Na Choon Piaw. All rights reserved */ /* This program and documentation is Public Domain, and may be */ /* distributed and copied by everyone provided this header */ /* remains intact */ /* MARS redcode assembler: Header file Restarted in Novemeber '88 Na Choon Piaw */ /* note that tag is just a generic name for something that I can't think of a name for. ---- CP */ /* define instruction set */ typedef enum { dat, mov, add, sub, jmp, jmz, jmn, djn, cmp, spl } instr; /* define addressing modes */ typedef enum { immed, direct, indirect } mode; /* define structure of an instruction */ /* NOTE: this will probably differ from the interpreter's version */ typedef struct { instr inst; /* instruction */ int para1,para2; /* first parameter, second parameter */ mode m1,m2; /* addressing modes for parameters */ } memory; /* memory element */ /* define compiler limits */ #define MAXINST 200 /* maximum number of instructions */ #define SYMBOLS 100 /* maximum number of symbols in symbol table */ #define MAXBUFFER 256 /* maximum size of string buffer */ #define COMMENT ';' /* comment character */ /* linked list of tokens for tokenizer and assembler to work on */ typedef struct tag0 { char *token; /* token as a string */ struct tag0 *next; /* next token */ } tokenlist; /* symbol table structure */ typedef struct { char *symbol; /* pointer to string of symbol */ int position; /* position the symbol belongs to */ } tag1; /* now to define the strings that the assembler recognizes */ #define MOV "MOV" #define ADD "ADD" #define SUB "SUB" #define JMP "JMP" #define JMZ "JMZ" #define JMN "JMN" #define DJN "DJN" #define CMP "CMP" #define SPL "SPL" #define DAT "DAT" !E!O!F! echo x - interp.h cat >interp.h <<'!E!O!F!' /* MARS redcode interpreter: Header file Started December '88 Na Choon Piaw */ /* instruction set */ typedef enum { dat, mov, add, sub, jmp, jmz, jmn, djn, cmp, spl } instr; /* addressing modes */ typedef enum { immed, direct, indirect } mode; /* this is the new definition of a memory cell */ typedef struct { instr inst; /* instruction */ int para1, para2; /* first parameter, second parameter */ mode m1, m2; /* addressing modes */ int lastmod; /* last modified by */ } cell; /* old assembler definition of memory cell */ typedef struct { instr inst; int para1, para2; mode m1, m2; } memory; /* doubly circularly linked list for streams of execution */ typedef struct tag0 { int pc; /* program counter */ struct tag0 *next, *prev; } stream; /* interpreter limits */ #define MAXINST 200 /* maximum number of instructions */ #define SIZE 8000 /* size of array */ #define MAXPLAY 3 /* maximum number of players */ #define RANDIVISOR 33 !E!O!F! echo x - amain.c cat >amain.c <<'!E!O!F!' /* this module contains the main function, which settles open/close file i/o as well as little trivial details like adding an extension and stuff like that. It has been debuged (except for BUG NOTES) so it's safe to trust. There is a little bit of inefficiency, but that's justified since I want a more easily readable program */ #include "assem.h" #include <stdio.h> #include <malloc.h> #include <strings.h> char *outname(str) char *str; /* accepts an input string and outputs a proper output file with ".e" extension. If already has .e, as an extension, produce an error. BUG NOTE: even if it's as innoculous as .eex, etc (as long as the extension starts with .e) it will still produce an error Otherwise, remove current extension and add .e extension. returns pointer to new output name */ { char *newstr; char *dot; /* position of '.' */ if (!(newstr =(char *) malloc( (unsigned) strlen(str) + 3))) { printf("not enough memory --- outname\n"); exit(1); } strcpy(newstr,str); if (!(dot = rindex(newstr,'.'))) strcat(newstr,".e"); /* no extenstion */ else if (*(dot + 1) == 'e') /* same extension as output? */ { printf("wrong input file name: %s\n", newstr); printf("try moving to non .e extension --- outname\n"); exit(1); } else /* perform surgery */ { (*(dot + 1)) = 'e'; (*(dot + 2)) = '\0'; } return newstr; } /* main -- Open input and output files, giving default names if necessary. Detects errors like not being able to open files etc. */ main(argc, argv) int argc; char *argv[]; { FILE *f1,*f2; /* input file, output file */ char *outfile = "NONAME", /* default output file */ flag = 0; /* standard input */ if (argc == 1) /* no arguments */ { flag = 1; /* read from standard input */ argv[1] = outfile; argc = 2; /* one file */ } for (;argc > 1; argc--) { if (flag) f1 = stdin; /* set file to standard input */ else /* open input file */ if (!(f1 = fopen(argv[argc - 1],"r"))) { printf("oops cannot open file %s", argv[argc - 1]); printf("\n-- in main\n"); exit(1); /* error status 1 */ } /* open output file */ if (!(f2 = fopen(outname(argv[argc - 1]), "w"))) { printf("cannot open write file %s", outname(argv[argc - 1])); printf("\n --- in main\n"); exit(1); } printf("%s:\n", argv[argc - 1]); assemble(f1,f2); /* call assembler */ if (!flag) /* close file */ fclose(f1); fclose(f2); } } /* debugging version of assemble */ /* commented out because this module is now fully debugged */ /* --- Na Choon Piaw, 11/14 */ /* assemble(infile,outfile) FILE *infile, *outfile; { int c; while ((c = fgetc(infile)) != EOF) fputc(c, outfile); } */ !E!O!F! echo x - aoutput.c cat >aoutput.c <<'!E!O!F!' /* Copyrighted (C) 1989 by Na Choon Piaw. All rights reserved */ /* This program and documentation is Public Domain, and may be */ /* distributed and copied by everyone provided this header */ /* remains intact */ /* output.c --- output routine for the asssembler. 11/25/88 --- NCP */ /* algorithm: 1. write number of instructions into file 2. write code number of start instruction 3. while there are still instructions do 4. write instruction n 5. end */ #include "assem.h" #include <stdio.h> #define IO(i,j) if ((i) < (j)) { printf("error in writing file --- output\n" \ ); } output(f, table, code, no) FILE *f; /* file to output to */ tag1 table[]; /* table of symbols */ memory code[]; /* code itself */ int no; /* number of instructions */ { int check, /* check on how many bytes have been written */ start; /* starting instruction */ check = fwrite(&no, sizeof(int), 1, f); IO(check,1) start = getsym("START",table); check = fwrite(&start, sizeof(int), 1, f); IO(check,1); check = fwrite(code, sizeof(memory), no, f); IO(check,no); } !E!O!F! echo x - assem.c cat >assem.c <<'!E!O!F!' /* Copyrighted (C) 1989 by Na Choon Piaw. All rights reserved */ /* This program and documentation is Public Domain, and may be */ /* distributed and copied by everyone provided this header */ /* remains intact */ /* assembler portion of the program */ /* 11/14 '88 Implementing a one-pass "text in memory" assembler that handle tokens as well. Symbol table is a linear table. Algorithm: 1) Tokenize the input file (i.e. produce a list of symbols in mem) 2) Run through once, parsing instructions but not turning into machine code yet. Insert all new symbols into symbol table. 3) Run through second time, turning it into machine code and looking up symbols. -- the real error phase. */ #include <stdio.h> #include <malloc.h> #include "assem.h" /* symbol table */ static tag1 table[SYMBOLS]; /* instructions list */ static memory elements[MAXINST]; /* declaring the functions */ tokenlist *tokenize(); /* top level connections for assembler hooks up tokenize, parse, lookup and output so that they can be written independently (no global variables in this program */ assemble(infile, outfile) FILE *infile,*outfile; { tokenlist *head; int i; /* number of instructions */ head = tokenize(infile); parse(head, table); i = lookup(head, table, elements); output(outfile, table, elements, i); } !E!O!F! echo x - disassem.c cat >disassem.c <<'!E!O!F!' /* Copyrighted (C) 1989 by Na Choon Piaw. All rights reserved */ /* This program and documentation is Public Domain, and may be */ /* distributed and copied by everyone provided this header */ /* remains intact */ #include <stdio.h> #include "assem.h" /* dissassembler for red code programs. NOTE: I'm not bothering with writing code to REALLY disassemble it, just output starting position, number of instructions, opcode, and operands. 11/25 ---- NCP */ #define IO(i,j) if ((i) < (j)) {printf("error reading file\n");exit(1);} main(argc, argv) int argc; char *argv[]; { FILE *f; int i,j,k; memory elements[MAXINST]; if (argc < 1) { printf("usage: disassem <file>\n"); exit(1); } if (!(f = fopen(argv[1],"r"))) { printf("cannot open file %s\n", argv[1]); printf("------ main\n"); exit(1); } i = fread(&j, sizeof(int), 1, f); IO(i,1) printf("Number of instructions: %d\n", j); i = fread(&k, sizeof(int), 1, f); IO(i,1) printf("Starting instruction: %d\n", k); i = fread(elements, sizeof(memory), j, f); IO(i,j) printf("NO.\tOPCODE\tFIRSTPARA\tSECONDPARA\n"); for (i = 0; i < j;i++) { printf("%d\t", i); printf("%d\t", (int) elements[i].inst); if (elements[i].m1 == immed) putchar('#'); else if (elements[i].m1 == indirect) putchar('@'); printf("%d\t\t", (int) elements[i].para1); if (elements[i].m2 == immed) putchar('#'); else if (elements[i].m2 == indirect) putchar('@'); printf("%d\n", (int) elements[i].para2); } fclose(f); } !E!O!F! echo x - inst.c cat >inst.c <<'!E!O!F!' /* execution code for the machine */ /* This is a replacement for the screwed up code in "execute.c" Each instruction is a function, and accepts just enough information to execute that instruction. */ #include "interp.h" #include <malloc.h> #include <stdio.h> extern cell a[]; /* core */ correct(thing) int *thing; { if (*thing >= 0) *thing %= SIZE; else if (*thing < 0) { *thing %= SIZE; *thing = SIZE + *thing; } } int getdirect(ins, off) /* get position of direct parameter */ int ins; /* current position */ int off; /* offset of instruction */ { int temp; temp = ins + off; correct(&temp); return (temp); } int getindirect(ins, off) /* get position of indirect parameter */ /* Note :- A.K. Dewdney's specifications say that the pointer points relative to its current position, NOT the instruction's position. */ int ins; int off; { int temp; /* temporary variable */ correct(&off); temp = getdirect(ins, off); /* get direct variable */ correct(&temp); /* correct it */ temp = getdirect(temp, a[temp].para2); /* This time it's for real */ correct(&temp); return (temp); } int getpara(ins, m, p) /* Note:- This routine is designed only to work with indirect and direct operations. NOT with immediate mode operations. Returns the address of the parameter by calling getdirect or getindirect */ int ins; /* location of current instruction */ mode m; /* mode */ int p; /* parameter */ { if (m == direct) return(getdirect(ins, p)); else if (m == indirect) return(getindirect(ins, p)); /* else */ printf("getpara passed wrong parameter --- getpara\n"); exit(1); } Mov (ins, pc, pid) /* MOV instruction : sets the lastmod flag to the process id */ int ins; /* position of instruction to execute */ int *pc; /* program counter */ int pid; /* process ID */ { int realpos; cell temp; /* store item to be moved */ if (a[ins].m1 == immed) { temp.inst = dat; temp.para1 = 0; temp.para2 = a[ins].para1; temp.m1 = temp.m2 = immed; } else { realpos = getpara(ins, a[ins].m1, a[ins].para1); temp = a[realpos]; } if (a[ins].m2 == immed) { printf("Tried to mov to immediate parameter\n"); printf("--- mov\n"); exit(1); } else realpos = getpara(ins, a[ins].m2, a[ins].para2); a[realpos] = temp; a[realpos].lastmod = pid; (*pc)++; correct(pc); } Add(ins, pc, pid) /* ADD instruction */ int ins; int *pc; int pid; { int x; /* parameter A */ int realpos; /* real position of B */ if (a[ins].m1 == immed) x = a[ins].para1; else x = a[getpara(ins, a[ins].m1, a[ins].para1)].para2; if (a[ins].m2 == immed) { printf("Trying to add to immediate address\n"); printf("--- ADD\n"); exit(1); } else realpos = getpara(ins, a[ins].m2, a[ins].para2); a[realpos].para2 += x; a[realpos].lastmod = pid; correct(&(a[realpos].para2)); (*pc)++; correct(pc); } Sub(ins, pc, pid) /* SUB instruction */ int ins; int *pc; { int x; /* parameter A */ int realpos; /* real position of B */ if (a[ins].m1 == immed) x = a[ins].para1; else x = a[getpara(ins, a[ins].m1, a[ins].para1)].para2; if (a[ins].m2 == immed) { printf("Trying to subtract from immediate address\n"); printf("--- SUB\n"); exit(1); } else realpos = getpara(ins, a[ins].m2, a[ins].para2); a[realpos].para2 -= x; a[realpos].lastmod = pid; correct(&(a[realpos].para2)); (*pc)++; correct(pc); } Jmp(ins,pc) int ins; int *pc; { if (a[ins].m2 == immed) { printf("attempt to jump to immediate address\n"); printf("-- JMP\n"); exit(1); } else *pc = getpara(ins, a[ins].m2, a[ins].para2); correct(pc); } Jmz(ins, pc) int ins; int *pc; { int value; /* value of first parameter */ if (a[ins].m2 == immed) value = a[ins].para2; else { value = getpara(ins, a[ins].m2, a[ins].para2); correct(&value); value = a[value].para2; } correct(&value); if (value) (*pc)++; else *pc = getpara(ins, a[ins].m1, a[ins].para1); correct(pc); } Jmn(ins,pc) int ins; int *pc; { int value; if (a[ins].m2 == immed) value = a[ins].para2; else { value = getpara(ins, a[ins].m2, a[ins].para2); correct(&value); value = a[value].para2; } if (!value) *pc = getpara(ins, a[ins].m1, a[ins].para1); else (*pc)++; correct(pc); } Djn(ins, pc, pid) int ins; int *pc; { int temp; /* position to decrement */ if (a[ins].m2 == immed) { printf("tried to decrement immediate address\n"); printf("--- DJZ\n"); exit(1); } else temp = getpara(ins, a[ins].m2, a[ins].para2); (a[temp].para2)--; correct(&(a[temp].para2)); a[temp].lastmod = pid; if (!a[temp].para2) (*pc)++; else *pc = getpara(ins, a[ins].m1, a[ins].para1); correct(pc); } Cmp(ins, pc) int ins; int *pc; { int value1, value2; if (a[ins].m1 == immed) value1 = a[ins].para1; else value1 = a[getpara(ins, a[ins].m1, a[ins].para1)].para2; if (a[ins].m2 == immed) value2 = a[ins].para2; else value2 = a[getpara(ins, a[ins].m2, a[ins].para2)].para2; correct(&value1); correct(&value2); if (value1 == value2) (*pc) += 2; else (*pc)++; correct(pc); } Spl(ins, pc, mem) int ins; int *pc; stream *mem; /* pointer to structure of current pc */ { int newpc; stream *newmem; if (a[ins].m2 == immed) { printf("Tried to split into immediate address\n"); printf("--- SPL\n"); exit(1); } else newpc = getpara(ins, a[ins].m2, a[ins].para2); if (!(newmem = (stream *) malloc(sizeof(stream)))) { printf("no more memory!!\n"); printf("--- SPL\n"); exit(1); } correct(&newpc); newmem -> pc = newpc; newmem -> next = mem -> next; mem -> next = newmem; newmem -> prev = mem; newmem -> next -> prev = newmem; (*pc)++; correct(pc); } extern stream *exe[]; Dat(i) /* kill stream */ int i; { stream *curr = exe[i]; /* current */ if (curr -> next == curr) { exe[i] = NULL; free(curr); return; } exe[i] = curr -> next; curr -> next -> prev = curr -> prev; curr -> prev -> next = curr -> next; free(curr); } !E!O!F! echo x - interp.c cat >interp.c <<'!E!O!F!' !E!O!F! echo x - load.c cat >load.c <<'!E!O!F!' /* program loader for MARS 12/16/88 --- NCP */ #include "interp.h" #include <stdio.h> #include <memory.h> #include <malloc.h> #define IO(i,j) if((i) < (j)){printf("error reading file\n");exit(1);} extern cell a[]; extern stream *exe[]; /* generates starting position */ /* debugging non random version */ int startposition() { /* debugging code: static int i = 0; if (i == 0) { i = 1; return(0); } else return((int) SIZE / 2) */ return(rand()%SIZE); } load(f, no) FILE *f; /* file */ int no; /* player number */ { memory ele[MAXINST]; int i; /* number of instructions */ int test; /* test instructions read */ int start; /* starting instruction */ int position; /* loading position */ int counter; /* general-purpose counter */ test = fread(&i, sizeof(int), 1, f); IO(test, 1) printf("Found %d/%d instructions\n", i, MAXINST); if (i > MAXINST) { printf("load: Oops! Too large!!\n"); return(1); /* oops - too large */ } test = fread(&start, sizeof(int), 1, f); IO(test, 1) test = fread(ele, sizeof(memory), i, f); IO(test, i) /* get a new starting position */ do { position = startposition(); printf("Trying position %d\n", position); } while (testpos(position,i)); /* and load the code there */ printf("Loading %d instructions at location %d\n", i, position); for (counter = 0; counter < i; counter++) { memcpy(&a[(counter+position)%SIZE],&ele[counter],sizeof(memory)); #ifdef DEBUG if (!(((counter+position)%SIZE)%10)) { printf("%d%",(counter+position)%SIZE); } else { putchar('.'); } #endif a[(counter+position)%SIZE].lastmod = no; printf("Contents of location %d: %d %d %d %d %d %d\n", (counter+position)%SIZE, a[(counter+position)%SIZE].inst, a[(counter+position)%SIZE].para1, a[(counter+position)%SIZE].para2, a[(counter+position)%SIZE].m1, a[(counter+position)%SIZE].m2, a[(counter+position)%SIZE].lastmod); } if ((exe[no] = (stream *) malloc(sizeof(stream))) == NULL) { printf("load: Can't malloc the PC - aborting\n"); exit(1); } else { exe[no]->pc = (position + start) % SIZE; exe[no]->next = exe[no]->prev = exe[no]; #ifdef DEBUG printf("Starting PC: %d %d %d\n", exe[no]->pc, exe[no]->next->pc, exe[no]->prev->pc); #endif } return(0); /* all OK */ } /* tests for empty segment of *no* bytes starting at *start* */ testpos(start,no) int start,no; { int counter; /* general-purpose counter */ for (counter = 0; counter < no; counter++) { #ifdef DEBUG if (!(((counter+start)%SIZE)%10)) { printf("%d%",(counter+start)%SIZE); } else { putchar('.'); } #endif if (a[(counter+start)%SIZE].lastmod) { printf("testpos: Oops -- something at %d\n",(counter+start)%SIZE); return(1); /* oops - clash */ } } return(0); /* all clear - segment is free */ } !E!O!F! echo x - lookup.c cat >lookup.c <<'!E!O!F!' /* Copyrighted (C) 1989 by Na Choon Piaw. All rights reserved */ /* This program and documentation is Public Domain, and may be */ /* distributed and copied by everyone provided this header */ /* remains intact */ /* lookup ---- this is the real core of the assembler. It will perform functions such as matching symbols to instructions, matching symbolic references to absolute code (and performing whatever calculations necessary). */ #include "assem.h" #include <malloc.h> #include <stdio.h> #include <strings.h> #include <ctype.h> /* declare external functions */ int symbol(); int instruction(); instr getin(); int para(); int getpara(); mode getmode(); /* algorithm :- 1) start from beginning of the list. 2) process element. 3) go on to next element. 4) return number of instructions */ int lookup(head, table, elements) tokenlist *head; tag1 table[]; memory elements[]; { int i = 0, /* instruction pointer */ j = 0, /* number of parameters */ k = 0; /* current parameters */ initialize(elements); /* initialize table */ while (head && symbol(head)) /* look for first instruction */ head = head -> next; while (head) { /* expect instruction */ if (!instruction(head)) { printf("%s is not instruction\n", head -> token); printf(" --- lookup\n"); exit(1); } elements[i].inst = getin(head); /* expect number of parameters */ j = para(head); k = 0; while (k < j) { head = head -> next; if (k == 0 && j == 2) /* if single para, put in B */ { elements[i].para1 = getpara(head,table,i); elements[i].m1 = getmode(head); } else { elements[i].para2 = getpara(head,table,i); elements[i].m2 = getmode(head); } k++; } if (head) head = head -> next; /* next instruction, if any */ while (head && symbol(head)) /* skim symbols */ head = head -> next; i++; } /* while */ return i; } /* set all instructions to init */ initialize(elements) memory elements[]; { memory ele; /* set all to this initialized variable */ int i; ele.inst = dat; ele.para1 = ele.para2 = 0; ele.m1 = ele.m2 = immed; for (i = 0; i < MAXINST; i++) elements[i] = ele; } /* get the instr part of an instruction */ instr getin(ptr) tokenlist *ptr; { char *t; /* string */ instr x; /* return value */ t = ptr -> token; if (!strcmp(t, DAT)) x = dat; else if (!strcmp(t, MOV)) x = mov; else if (!strcmp(t, ADD)) x = add; else if (!strcmp(t, SUB)) x = sub; else if (!strcmp(t, JMP)) x = jmp; else if (!strcmp(t, JMZ)) x = jmz; else if (!strcmp(t, JMN)) x = jmn; else if (!strcmp(t, DJN)) x = djn; else if (!strcmp(t, CMP)) x = cmp; else if (!strcmp(t, SPL)) x = spl; else { printf("%s is not an instruction\n", t); printf("--- getin\n"); exit(1); } return x; } /* getin */ /* get the actual parameter (not the symbolic one) Algorithm: 1) check if symbol 2) if symbol then look up, compare with current instruction, and calculate what the actual parameter should be. 3) if not symbol, then check that it is a numeric. if not, error. 4) otherwise, return atoi */ int getpara(ptr, table, curr) tokenlist *ptr; /* parameter instruction */ tag1 table[]; /* symbol table */ int curr; /* current instruction */ { char *t; /* token string */ t = ptr -> token; if (*t == '@' || *t == '#') /* ignore these */ t++; if (number(t)) return(atoi(t)); else /* must be symbol */ return(getsym(t, table) - curr); } /* return the absolute location (from the beginning of the program) of a symbol */ int getsym(str, table) char *str; tag1 table[]; { int i = 0; char s[MAXBUFFER]; /* add colon for strcmp */ strcpy(s,str); strcat(s,":"); for (; (i < SYMBOLS) && (table[i].symbol != NULL); i++) if (!strcmp(table[i].symbol, s)) return(table[i].position); /* out here, not symbol */ printf("symbol %s undefined\n", str); printf("--- getsym\n"); exit(1); } /* checks that every element in string is a digit */ int number(str) char *str; { int i = 1; if (*str == '+' || *str == '-') /* positive or negative */ str++; while (*str && i) { if (!isdigit(*str)) i = 0; str++; } return i; } mode getmode(ptr) tokenlist *ptr; { char *t; /* token string */ t = ptr -> token; if (*t == '@') return(indirect); else if (*t == '#') return(immed); else return(direct); } /* special debugging portion */ /* declared debugged (phew! this one was tough) on 11/23/88 by CP */ /* tokenlist *tokenize(); tag1 table[SYMBOLS]; memory elements[MAXINST]; extern tokenlist *tokenize(); main(argc, argv) int argc; char *argv[]; { tokenlist *head; FILE *f; int i; printf("loaded\n"); f = fopen(argv[1],"r"); printf("%s file opened\n", argv[1]); head = tokenize(f); printf("tokenized\n"); parse(head, table); printf("parsed\n"); i = lookup(head, table,elements); printf("%d instructions\n", i); printf("OPCODE\tFIRSTPARA\tSECONDPARA\n"); for (i = 0; i < 20; i++) { printf("%d\t",(int) elements[i].inst); if (elements[i].m1 == indirect) printf("@"); else if (elements[i].m1 == immed) printf("#"); printf("%d\t\t", elements[i].para1); if (elements[i].m2 == indirect) printf("@"); else if (elements[i].m2 == immed) printf("#"); printf("%d\n", elements[i].para2); } fclose(f); } printsymbols(head) tokenlist *head; { while (head != NULL) { printf("%s\n", head -> token); head = head -> next; } } printable(t) tag1 t[]; { int i; printf("%s\t%s\n","SYMBOL","POSITION"); for (i = 0; table[i].symbol != NULL; i++) printf("%s\t%d\n", table[i].symbol,table[i].position); } */ !E!O!F! echo x - main.c cat >main.c <<'!E!O!F!' /* main program for MARS interpreter As usual, this does not do anything important. Just calls all the proper subroutines in the right order and opens files. -- 12/16/88 --- NCP */ #include "interp.h" #include <ctype.h> #include <stdio.h> #include <memory.h> #include <curses.h> long atol(); /* memory array -- called "a" for easy typing */ cell a[SIZE]; /* next execution for each player */ stream *exe[MAXPLAY]; /* returns which player won */ int play(); usage() { printf("usage: interp cycles file1 file2\n"); printf("--- main\n"); } /* checks that every element in string is a digit */ int number(str) char *str; { int i = 1; while (*str && i) { if (!isdigit(*str)) i = 0; str++; } return i; } initialize() { int counter; /* general-purpose counter */ counter = (int) time(0); #ifndef DEBUG initscr(); /* for "curses" library */ scrollok(stdscr, 0); nl(); clear(); refresh(); #endif srand(counter); for (counter = 0; counter++; counter < SIZE) memset(a[counter],0,sizeof(cell)); } main(argc, argv) int argc; char *argv[]; { FILE *f; int errcode, result; initialize(); /* initialize all global variables */ if (argc != 4) /* too many or too few */ { usage(); exit(1); } if (!(number(argv[1]))) { usage(); exit(1); } if ((f = fopen(argv[2], "r")) == NULL) { printf("%s cannot be opened\n", argv[2]); exit(1); } errcode = load(f, 1); fclose(f); if (errcode == 1) { printf("main: Sorry, but %s is too large to load\n",argv[2]); exit(1); } if ((f = fopen(argv[3], "r")) == NULL) { printf("%s cannot be opened\n", argv[3]); exit(1); } errcode = load(f,2); fclose(f); if (errcode == 1) { printf("main: Sorry, but %s is too large to load\n",argv[3]); exit(1); } #ifndef DEBUG clear(); #endif result = play(atol(argv[1])); #ifndef DEBUG output(0); move(21, 0); if (!result) printw("nobody won!"); else printw("%s won!", argv[result + 1]); move(22, 0); printw("Hit any key to continue..."); refresh(); getch(errcode); endwin(); #endif } !E!O!F! echo x - output.c cat >output.c <<'!E!O!F!' /** Output function **/ #include <stdio.h> #include <curses.h> #include "interp.h" extern cell a[]; #if DEBUG output() { int i; for (i = 0; i < SIZE; i ++) { if (a[i].lastmod == 0) putchar('0'); else if (a[i].lastmod == 1) putchar('1'); else if (a[i].lastmod == 2) putchar('2'); else { printf("\nerror lastmod == %d", a[i].lastmod); printf("i == %d", i); exit(1); } } putchar('\n'); } #endif #ifdef SMALL /* assume large, 80 col screen */ output(cycles) long cycles; { int map[SIZE / 5]; /* map to one fifth the size */ int i, j, k = 0; move(0,0); /* start from the top */ domap(map); for (i = 0; i < SIZE/5;) { move(k, 0); for (j = 1; j < COLS; i++, j++) { if (SIZE / 5<= i) break; if (map[i] == 0) addch('0'); else if (map[i] == 1) addch('1'); else if (map[i] == 2) addch('2'); } k++; } move(23, 0); printw("Cycles left: %10d", cycles); refresh(); } domap(arr) int arr[]; { int i, j, pid1, pid2, pid3; for (j = 0; j < SIZE/5; j++) { pid1 = pid2 = pid3 = 0; for (i = j * 5; i < (j+1) * 5; i++) { if (SIZE <= i) break; if (a[i].lastmod == 0) pid1++; else if (a[i].lastmod == 1) pid2++; else if (a[i].lastmod == 2) pid3++; else { printf("invalid modification detected\n"); printf("--- domap\n"); exit(1); } } arr[j] = max(pid1, pid2, pid3); } } max(i, j, k) int i, j, k; { if (i > j && i > k) return 0; else if (j > i && j > k) return 1; else return 2; } #endif #ifdef BIG output(cycles) int cycles; { int i, j, k; /* perform detailed mapping */ for (i = 0, k = 0; i < SIZE; k++) { move (k, 0); for (j = 0; j < COLS; i++, j++) { if (i >= (SIZE - 1)) break; /* else */ if (a[i].lastmod == 0) addch('0'); if (a[i].lastmod == 1) addch('1'); else addch('2'); } } move (k + 2, 0); printw("Cycles left: %10d\n", cycles); refresh(); } #endif !E!O!F! echo x - parse.c cat >parse.c <<'!E!O!F!' /* Copyrighted (C) 1989 by Na Choon Piaw. All rights reserved */ /* This program and documentation is Public Domain, and may be */ /* distributed and copied by everyone provided this header */ /* remains intact */ /* parser portion of the assembler. 11/15/88 - NCP */ #include <strings.h> #include <stdio.h> #include "assem.h" /* parser: Algorithm: 1) initialize symbol table 2) Scan first element in token list 3) if symbol declaraion (e.g. "start:") then lookup and enter into symbol table 4) if instruction, skip forward number of parameters that instruction accepts 5) otherwise error (not instruction or symbol) 6) repeat 3-6 until no more tokens. */ parse(tokens,table) tokenlist *tokens; /* list of tokens */ tag1 table[]; /* symbol table */ { int i = 0; /* instructon counter */ init(table); /* initialize table */ while (tokens) { if (symbol(tokens)) { insert(tokens,table,i); tokens = tokens -> next; } else if (instruction(tokens)) { int j = 0, k = para(tokens); /* move up to next instruction: i.e., move from instruction + number of parameters if instruction is one parameter, move twice, etc */ while (j <= k) { tokens = tokens -> next; j++; } i++; /* next instruction */ } else /* not instruction or symbol */ { printf("%s not symbol or instruction\n", tokens -> token); printf(" --- parse\n"); exit(1); } } /* while */ /* test for too many instructions */ if (i > MAXINST) { printf("too many instructions\n"); printf("---- parse\n"); exit(1); } } /* parse */ init(table) /* function to initialize symbol table (set to 0 */ tag1 table[]; { int i; for (i = 0; i < SYMBOLS; i++) { table[i].symbol = NULL; table[i].position = 0; } } int symbol(tok) /* identifies a symbol: A symbol is just a token that ends with a ':' */ tokenlist *tok; { char *t; /* token string */ t = tok -> token; if ((t[strlen(t) - 1]) == ':') /* address last character */ return 1; /* is symbol declaration */ else return 0; } /* inserts a token into a symbol table (without stripping the ':') - Algorithm: 1) search until symbol table reads a NULL string or the new symbol is equal to and old one. 2) if the new symbol is not a NULL, then error otherwise, insert 3) if out of space, error */ int insert(tok, table, no) tokenlist *tok; /* token */ tag1 table[]; /* symbol table */ int no; /* instruction number */ { char *t; /* token string */ int i = 0; /* index on table */ t = tok -> token; /* search for empty place in table */ for (; i < SYMBOLS && table[i].symbol != NULL && (strcmp(table[i].symbol,t) != 0); i++) ; if (table[i].symbol != NULL) { printf("symbol %s already declared\n", t); printf("--- insert\n"); exit(1); } table[i].symbol = t; table[i].position = no; } /* tests whether instruction */ int instruction(tok) tokenlist *tok; { char *t; /* token string */ t = tok -> token; /* note that due to a quirk in strcmp (it returns a zero if the strings are equal) this looks particularly convoluted, but the logic is simple. */ return(! (strcmp (t,MOV) && strcmp (t,ADD) && strcmp (t,SUB) && strcmp (t,JMP) && strcmp (t,JMZ) && strcmp (t,JMN) && strcmp (t,DJN) && strcmp (t,CMP) && strcmp (t,SPL) && strcmp (t,DAT))); } /* return the number of parameters an instruction has */ int para(tok) tokenlist *tok; { char *t; /* token string */ int i = 0; /* return value */ t = tok -> token; /* use a multiple if-elseif statement */ if (!strcmp(t, MOV)) i = 2; else if (!strcmp(t, ADD)) i = 2; else if (!strcmp(t, SUB)) i = 2; else if (!strcmp(t, JMP)) i = 1; else if (!strcmp(t, JMZ)) i = 2; else if (!strcmp(t, JMN)) i = 2; else if (!strcmp(t, DJN)) i = 2; else if (!strcmp(t, CMP)) i = 2; else if (!strcmp(t, SPL)) i = 1; else if (!strcmp(t, DAT)) i = 1; else /* unrecognized instruction */ { printf("%s is not an instruction\n", t); printf("--- para\n"); exit(1); } return(i); } /* para */ /* debugging section of parse.c */ /* code commented out --- given a clean bill of health by Dr. Na Choon Piaw --- 11/15/88 */ /* declare tokenize */ /* extern tokenlist *tokenize(); */ /* declare symbol table */ /* tag1 table[SYMBOLS]; */ /* main(argc,argv) int argc; char *argv[]; { tokenlist *head; FILE *f; int i; f = fopen(argv[1], "r"); head = tokenize(f); parse(head, table); printf("%s\t%s\n", "SYMBOL", "POSITION"); for (i = 0; table[i].symbol != NULL; i++) printf("%s\t%d\n", table[i].symbol, table[i].position); } */ !E!O!F! echo x - play.c cat >play.c <<'!E!O!F!' /* play.c ---- main program for the interpreter. 1. play player 1 2. play player 2 3. output 4. check deaths 5. repeat --- 12/17/88 NCP */ #include <stdio.h> #include "interp.h" extern stream *exe[]; extern cell a[]; int dead(i) int i; { if (exe[i]) return 0; else return 1; } int alive() { int i, j = 1; for (i = 1; i < MAXPLAY; i ++) { if (!exe[i]) { j = 0; break; } } return(j); } int play(cycles) long cycles; { int i; while (alive() && cycles) { for ( i = 1; i < MAXPLAY; i++) { execute(i); /* play player n */ #ifdef DEBUG output(); #endif #ifdef BIG output(cycles); #endif } #ifdef SMALL if (!(cycles % 100)) output(cycles); #endif cycles --; } if (dead(1) && !dead(2)) return(2); /* process 2 won */ else if (dead(2) && !dead(1)) return(1); /* process 1 won */ else return(0); /* nobody won */ } execute(i) int (i); { instr temp; /* instruction */ int x; /* cell to execute */ int pc; if (exe[i] == NULL) return; correct(&(exe[i] -> pc)); x = pc = exe[i] -> pc; temp = a[x].inst; /* this really should have been a switch-case, but I'm using an elongated if-else because the compiler doesn't accept it. */ if (temp == dat) Dat(i); else if (temp == mov) Mov(x, &pc, i); else if (temp == add) Add(x, &pc, i); else if (temp == sub) Sub(x, &pc, i); else if (temp == jmp) Jmp(x, &pc); else if (temp == jmz) Jmz(x, &pc); else if (temp == jmn) Jmn(x, &pc); else if (temp == djn) Djn(x, &pc, i); else if (temp == cmp) Cmp(x, &pc); else if (temp == spl) Spl(x, &pc, exe[i]); else { printf("Instruction not recognized\n"); printf("--- execute\n"); printf("opcode: %d", temp); printf(" executing no: %d", pc); printf(" process: %d\n", i); exit(1); } if (temp != dat) exe[i] -> pc = pc; if (exe[i] && (temp != dat)) exe[i] = exe[i] -> next; } !E!O!F! echo x - test.c cat >test.c <<'!E!O!F!' main() { int i, j; for (i = 0; i <8000;) { for (j = 0; j < 10; j++, i++) printf("%d", j); } } !E!O!F! echo x - tokenize.c cat >tokenize.c <<'!E!O!F!' /* Copyrighted (C) 1989 by Na Choon Piaw. All rights reserved */ /* This program and documentation is Public Domain, and may be */ /* distributed and copied by everyone provided this header */ /* remains intact */ /* tokenize ---- tokenizer for the assembler. It splits up all of the tokens in the given input file, generate a linked list of such tokens, and outputs the pointer to that linked list. 11/14 ----- NCP */ #include <stdio.h> #include <ctype.h> #include <strings.h> #include <malloc.h> #include "assem.h" /* tokenize function: separate input stream (infile) into tokens. algorithm: 1) call nextoken to get next token. 2) if "null" then return the first pointer 3) otherwise, add the newtoken to the token list 4) go back to 1. */ tokenlist *tokenize(infile) FILE *infile; { tokenlist *head, *tail, *newtail; char *nextoken(), *newtoken; head = tail = NULL; while ((newtoken = nextoken(infile)) != NULL) { if (!(newtail = (tokenlist *) malloc((unsigned) sizeof(tokenlist)))) { printf("ran out of space for tokens: %s\n", newtoken); printf("------ tokenize\n"); exit(1); } /* otherwise , set old stuff to this and move tail one up*/ newtail -> token = newtoken; newtail -> next = NULL; if (tail) /* tail already defined */ { tail -> next = newtail; /* set previous ptr */ tail = tail -> next; /* move up list */ } else head = tail = newtail; } /* end while */ return (head); /* return function value */ } /* function next token: return next token in the file. Algorithm: 1) read until start of next token or EOF 2) if EOF then return NULL pointer 3) read new token into buffer 4) malloc new string 5) put next token into new string 6) change all characters into upper case 7) return pointer to string created in (4) */ /* BUG NOTE: Due to the way it is written, the assembler will not process things like "mov0 1" correctly, and neither will "mov 0 1;imp" work. this is because the tokenize breaks everything down that isn't a delimiter, and a ";" is not a delimiter, even though it's not in the instruction set. NCP - 11/15/88 */ char *nextoken(infile) FILE *infile; { char buffer[MAXBUFFER], /* string buffer */ *newtoken; /* new token pointer */ int c, /* character we read in one by one */ i = 0; /* integer counter */ while ((c = fgetc(infile)) != EOF) { if (!isspace(c)) break; /* not space, so process */ } if (c == EOF) return(NULL); /* no more!! */ if (c == COMMENT) /* handle comments */ { while (((c = fgetc(infile)) != '\n') && c != EOF) ; /* read until end of the line */ if (c == EOF) return(NULL); /* process the rest of the file: actually, we could have done this by using a goto the beginning of this function, but I think this is a lot more elegant --- CP */ return(nextoken(infile)); } while ((!isspace(c)) && (c != EOF)) /* read until next space */ { if (i >= MAXBUFFER) /* buffer out */ { printf("buffer over extended\n"); printf("--- nextoken\n"); exit(1); } buffer[i++] = c; c = fgetc(infile); } /* end while */ buffer[i] = '\0'; /* terminate with a null */ if (!(newtoken = (char *) malloc( (unsigned) strlen(buffer) + 1))) { printf("not enough memory for token %s\n", buffer); printf(" ------- nextoken\n"); exit(1); } strcpy(newtoken, buffer); upcase(newtoken); return(newtoken); } /* end of nextoken */ /* upcase function -- translate string to upper case (don't trust toupper) */ upcase(str) char *str; { while (*str) { if ((*str <= 'z') && (*str >= 'a')) *str -= 'a' - 'A'; str++; } } /* special main to test the above */ /* section commented out because code has been fully debugged and given a clean bill of health CP - 11/14/88 main(argc,argv) int argc; char *argv[]; { FILE *f; tokenlist *head; f = fopen(argv[1],"r"); head = tokenize(f); while (head != NULL) { printf("%s\n", head -> token); head = head -> next; } } */ !E!O!F! echo x - bomb.rc cat >bomb.rc <<'!E!O!F!' start: mov #0 @ptr add #1 ptr jmp start ptr: dat #1 !E!O!F! echo x - chang1.rc cat >chang1.rc <<'!E!O!F!' ; chang 1 corewars program mov #0 -1 jmp -1 ;;nothing dat +9 ;complete tester start: spl -2 spl 4 add #-16 -3 ; nothing mov #5 @-4 help: jmp -4 spl 2 jmp -1 finish: next: odd: mov 0 1 finito: !E!O!F! echo x - commando.rc cat >commando.rc <<'!E!O!F!' ;;; an implementation of a k dewdney's commando program count: dat #14 ptr: dat #200 imps: mov #0 -1 ; imp stomper jmp imps mov #14 count mov #100 ptr start: mov imp 1000 spl 999 loop: mov @count @ptr sub #1 ptr djn loop count add #4 ptr spl @ptr jmp imps imp: mov 0 1 !E!O!F! echo x - dwarf.rc cat >dwarf.rc <<'!E!O!F!' dat -1 start: add #5 -1 mov #0 @-2 JMP -2 !E!O!F! echo x - dwarfgun.rc cat >dwarfgun.rc <<'!E!O!F!' ;;; dwarfgun program. ;;; Choon Piaw stomp: mov #0 -1 jmp stomp start: spl init jmp stomp count: dat #4 ptr: dat #500 ;;;; dwarf part dwf: dat #5000 loop: mov #0 @dwf djn loop dwf ;;; initialization init: mov #-200 ptr2 mov #0 count2 mov #500 ptr mov #4 count ;;; dwarf copy part dwfcp: mov @count @ptr sub #1 ptr djn dwfcp count add #3 ptr spl @ptr ; leave dwarf running. ;;;; copy self upstream selfcp: mov @count2 @ptr2 sub #1 count2 sub #1 ptr2 cmp count2 #-27 jmp selfcp add #3 ptr2 jmp @ptr2 ptr2: dat #-200 count2: dat #0 !E!O!F! echo x - gemini.rc cat >gemini.rc <<'!E!O!F!' dat #0 dat #99 start: mov @-2 @-1 cmp -3 #9 jmp 4 add #1 -5 add #1 -5 jmp -5 mov #99 93 jmp 93 !E!O!F! echo x - imp.rc cat >imp.rc <<'!E!O!F!' start: mov 0 1 !E!O!F! echo x - impstomp.rc cat >impstomp.rc <<'!E!O!F!' start: mov #0 -1 jmp start !E!O!F! echo x - mice.rc cat >mice.rc <<'!E!O!F!' ; mouse program --- The First Core War tournament ptr: dat #0 ;hell start: mov #9 ptr ;you loop: mov @ptr @7 ;know sub #1 6 djn loop ptr ;i hate testing add #1 4 spl @3 ;assemblers add #653 2 ;like jmz -7 -8 ;this dat 833 !E!O!F! echo x - selfcpy.rc cat >selfcpy.rc <<'!E!O!F!' imps: mov #0 -1 jmp imps start: spl imps jmp loop count: dat #7 ptr: dat #57 mov #7 count mov #57 ptr loop: mov @count @ptr sub #1 ptr djn loop count jmp 46 !E!O!F! echo x - sit.rc cat >sit.rc <<'!E!O!F!' start: jmp start !E!O!F! echo x - testspl.rc cat >testspl.rc <<'!E!O!F!' start: spl after mov #0 -3 jmp -1 after: mov 0 1 !E!O!F! An Existentialist c60a-3ci@wolf.berkeley.edu %flames >/dev/null "Do you think that if I stopped thinking so much I'd have less trouble?"
blojo@soda.berkeley.edu (05/21/91)
An X11r4 version of Core War is available for ftp from soda.berkeley.edu (128.32.131.179). It currently requires a workstation running X11r4 with something like 8-plane color to run; black-and-white support may be added in future. For those of you without color, a constantly-updated Redcode archive will be kept at the same site. Please mail me any code not already contained in the collection. The program source lives on soda in pub/corewar/corewar.tar.Z; the constantly updated Redcode is (bundled together) in pub/corewar/redcode.tar.Z, and (separate) in pub/corewar/redcode/. Prior to putting together this package, I searched far and wide through various ftp sites for prior implementations of Core War; I can safely say that this is by far the most excellent version of Core War I've seen. - Jon (blojo@soda.berkeley.edu)