/***********************************************************************/
/* Emulator belonging to the Chessiverse 1.1 */
/* This program reads a code image from the state file 'chessi.sav', */
/* on which the urviving programs are periodically saved. This code */
/* is then run on a number of randomly generated board position, */
/* printing a trace of the executed code, including disassembly of all */
/* executed instruction, and register contents specifying the machine */
/* state. */
/***********************************************************************/
/* 1.0.1: OUT instruction in interpreter as wrong if mode != 7 */
#include <stdio.h>
/* Parametric description of tournament */
#define CHAMBERS 1 /* number of different enironments */
#define BOARDS 50
#define PROGRAMS (2*BOARDS) /* number of programs per chamber */
#define ROUNDS 100 /* number of games per season */
#define RECORD 1000 /* save every so many seasons */
#define BRDSIZE 64 /* size of game board */
#define TWEIGHT 0 /* weight of CPU time in score */
#define TLIMIT 1000 /* timeout in nr of instructions */
/* Description of virtual machines */
#define DATAMEM 0x1000
#define PROGMEM 0x1000
#define FRAME 0x100 /* size of local-variables stack frame */
/* piece encodings in environment */
#define WHITE 8
#define BLACK 16
#define WPAWN 1
#define BPAWN 2
#define KNIGHT 3
#define BISHOP 4
#define ROOK 5
#define QUEEN 6
#define KING 7
/* Breeding parameters */
#define SURVIVORS 25
#define IMPORTS 0
#define PARENTS (SURVIVORS + IMPORTS)
#define MUTATIONS 10
unsigned short int Prog[PROGMEM];
unsigned char Data[DATAMEM];
unsigned char OutBuf[256];
char Table[BRDSIZE+2]; /* chess boads, incl. stm and cnt30 */
unsigned long long int Seed = 0x55555555;
int Draw(int n)
/* generate random integer from 0 to n-1 */
{
Seed = Seed * 0x20001083;
return ((Seed>>48)*n >> 16);
}
char *opcotab[32] = {
"ADD", "INC",
"SUB", "DEC",
"AND", "LSL",
"OR ", "LSR",
"XOR", "ASR",
"MUL", "NEG",
"UML", "COM",
"LD ", "CLR",
"BIT", "TST",
NULL, "ST ",
NULL, "IDX",
NULL, NULL,
NULL, NULL,
"rmw", "RTS",
"Bcc", "SOB",
"JSR", "JSR"
};
char *conditab[8] = {
"BEQ", "BNE", "BPL", "BMI", "BCC", "BCS", "BVC", "BVS" };
char *modetab[] = {
" %x%x(SP)", "1%x%x(SP)", "2%x%x(SP)", "3%x%x(SP)",
" %x%x", "*%x%x", "*%x%x(SP)", "$%x%x"
};
disas(unsigned short int *Prog, int addr)
/* disassemble one line at addr in given program */
{
int i, j, k, opc, mode, offs, instr;
instr = Prog[addr];
printf("%4x %4x ", addr, instr);
if((instr&0xF000) == 0xF000) printf("JSR %3x", instr&0xFFF); else
if((instr&0xFF00) == 0x9700) printf("INP %2x", instr&0xFF); else
if((instr&0xFF00) == 0xA700) printf("OUT %2x", instr&0xFF); else
{
opc = instr >> 11;
mode = instr >> 8 & 7;
offs = instr & 0xFF;
if(opcotab[opc] == NULL) printf("NOP"); else
if(opc == 26) printf("%sA", opcotab[2*mode+1]); else
if(opc == 27) printf("RTS"); else
if(opc == 28) printf("%s %3x", conditab[mode], addr + 1 + offs); else
if(opc == 29) printf("SOB %d, %3x", mode, addr + 1 - offs); else
{
printf("%s ", opcotab[opc]);
if((opc&1) && mode == 7) printf("@");
else printf(modetab[mode], offs>>4, offs&15);
}
}
printf("\n");
}
int Run(unsigned short int *Code, unsigned char *Port,
int MaxPort, int OPlim, int Ilim)
/* interpret virtual-machine code passed in 'Code' for 'Ilim' */
/* instructions, or until 'OPlim' outputs are produced. */
{
unsigned int SP, PC, IX, IR, ADR, ACCU, CC, VAL, PNR, Opcode;
int i, j, k, h, Mode, Optr=0, Icnt=0;
for(i=0; i<DATAMEM; i++) Data[i] = 0; /* clear data memory */
PC = 0x200; SP = DATAMEM - FRAME; /* initialize registers */
IX = ADR = PNR = 0;
printf(" SP IX PNR ADR CC ACCU PC IR instruction\n");
while(1)
{
if(Icnt++ > Ilim) return Icnt; /* Stop when time-out */
printf("%3x %4x %2x %3x %4x %4x ",
SP, IX, PNR, ADR, CC&0xFFFF, ACCU&0xFFFF);
disas(Code, PC);
PC &= PROGMEM-1;
IR = Code[PC++]; /* fetch next instruction */
Opcode = IR>>11;
if(Opcode >= 26) /* jump, branch or reg-mode */
{ /* have deviating formats */
if(Opcode >= 30) /* JSR <address> */
{
SP -= FRAME; /* reserve new stack frame */
if(SP<0x100) return TLIMIT; /* stack overflow */
Data[SP+8] = PC; /* save return address */
Data[SP+9] = PC>>8;
PC = IR & (PROGMEM-1); /* load program counter */
continue;
}
Mode = IR>>8 & 7;
switch(Opcode)
{
case 26: /* accumulator unaries */
switch(Mode)
{
case 0: CC = ++ACCU; break; /* INC %a */
case 1: CC = --ACCU; break; /* DEC %a */
case 2: CC = ACCU <<= 1; break; /* LSL %a */
case 3: CC = ACCU >>= 1; break; /* LSR %a */
case 4: CC = ACCU >>= 1; break; /* ASR %a */
case 5: CC = ACCU = -ACCU; break; /* NEG %a */
case 6: CC = ACCU = ~ACCU; break; /* COM %a */
case 7: CC = ACCU = 0; break; /* CLR %a */
} continue;
case 27: /* RTS */
PC = Data[SP+8] + (Data[SP+9]<<8);
if(SP >= DATAMEM-FRAME) return TLIMIT; /* stack underflow */
SP += FRAME; continue;
case 28: /* conditional branches */
switch(Mode)
{ /* Branch forward if condition true */
case 0: if(CC==0 ) PC += IR & 0xFF; continue; /*BEQ*/
case 1: if(CC!=0 ) PC += IR & 0xFF; continue; /*BNE*/
case 2: if((CC&0x80)==0 ) PC += IR & 0xFF; continue; /*BPL*/
case 3: if((CC&0x80)!=0 ) PC += IR & 0xFF; continue; /*BMI*/
case 4: if((CC&~0xFF)==0) PC += IR & 0xFF; continue; /*BCC*/
case 5: if((CC&~0xFF)!=0) PC += IR & 0xFF; continue; /*BCS*/
case 6: if((CC^CC>>8)&0x80==0) PC += IR & 0xFF; continue;
case 7: if((CC^CC>>8)&0x80!=0) PC += IR & 0xFF; continue;
}
case 29: /* SOB ctr, <backward> */
if(CC=Data[SP+Mode]--) PC -= IR & 0xFF;
continue;
}
}
if(Opcode>21) continue;
/* Normal addressing mode, calculate address and fetch data */
Mode = IR>>8 & 7;
h = 0;
switch(Mode)
{
case 1: /* adjust offset for access */
case 2: /* of deeper stack frames */
case 3:
h = Mode * FRAME;
case 0: /* local-frame address */
case 6: /* add stack pointer */
h += SP;
case 4: /* base address + indexing */
case 5:
h += (IX + IR) & 0xFF; IX = 0;
ADR = h & DATAMEM-1; /* prevent memory violation */
if(Mode>4) ADR = Data[ADR]; /* mode 5&6: indirection */
VAL = Data[ADR]; break; /* fetch data */
case 7:
VAL = IR & 0xFF; /* immediate mode */
PNR = (VAL + IX) & 0xFF; /* Port number */
if(IX) VAL = Code[PNR]; /* or constant-table mode */
}
/* perform operation, remembr result in CC for branching */
switch(Opcode)
{
/* binary operations, performed in accumulator */
case 0: CC = ACCU += VAL; continue; /* ADD <memory> */
case 2: CC = ACCU -= VAL; continue; /* SUB <memory> */
case 4: CC = ACCU &= VAL; continue; /* AND <memory> */
case 6: CC = ACCU |= VAL; continue; /* OR <memory> */
case 8: CC = ACCU ^= VAL; continue; /* XOR <memory> */
case 10: CC = ACCU = (char) ACCU * (char) VAL;
continue; /* MUL <memory> */
case 12: CC = ACCU *= VAL; continue; /* UML <memory> */
case 14: CC = ACCU = VAL; continue; /* LD <memory> */
case 16: CC = ACCU &= VAL; continue; /* AND <memory> */
case 18: if(Mode==7) /* INP <port> */
{ CC = ACCU = PNR < MaxPort ? Port[PNR] : Draw(256);
IX = 0;
} continue;
case 20: if(Mode==7)
{ OutBuf[Optr++] = ACCU; /* OUT <port> */
if(Optr>=OPlim) return Icnt; /* enough output */
} continue;
/* unary operators, directly in memory (read-modify-write) */
case 1: Data[ADR] = CC = Data[ADR] + 1; continue; /* INC <memory> */
case 3: Data[ADR] = CC = Data[ADR] - 1; continue; /* DEC <memory> */
case 5: Data[ADR] = CC = Data[ADR] <<1; continue; /* LSL <memory> */
case 7: Data[ADR] = CC = Data[ADR] >>1; continue; /* LSR <memory> */
case 9: Data[ADR] = CC = Data[ADR] >>1; continue; /* ASR <memory> */
case 11: Data[ADR] = CC = -Data[ADR]; continue; /* NEG <memory> */
case 13: Data[ADR] = CC = ~Data[ADR]; continue; /* COM <memory> */
case 15: Data[ADR] = CC = 0; continue; /* CLR <memory> */
case 17: CC = Data[ADR]; continue; /* TST <memory> */
case 19: Data[ADR] = CC = ACCU; continue; /* ST <memory> */
case 21: IX = 0x8000 | Data[ADR]; continue; /* IDX <memory> */
}
}
}
void IniBoard(char *board, int chamber)
/* Initialize new game according to chamber rules */
{
int i, j;
for(i=0; i<BRDSIZE+2; i++) board[i] = 0;
switch(chamber)
{ /* add rules for other chambers here */
default:
/* Position of KQK end-game */
board[Draw(64)+2] = WHITE + QUEEN;
i = Draw(64);
board[i+2] = WHITE + KING;
j = Draw(63); if(j>=i) j++; /* make sure Kings do not */
board[j+2] = BLACK + KING; /* end up on same square */
board[0] = Draw(2); /* randomize side to move */
}
}
char Dir[] = {0,0,4,22,17,8,13,13};
char Slider[] = {0,0,0,0,1,1,1,0};
char Xvec[] = {0,1,-1,0, 0,1,-1,0, 1,0,-1, 0,0, 1,0,-1, 0,1,-1, 1,-1,0,
2,-2,1,-1, 2,-2, 1,-1,0};
char Yvec[] = {1,0, 0,0,-1,0, 0,0, 0,1, 0,-1,0, 0,1, 0,-1,1, 1,-1,-1,0,
1, 1,2, 2,-1,-1,-2,-2,0};
int LegalMove(char *Board, unsigned char *Move)
/* perform move if legal and check for K-capture */
/* Return -1, 0 or 1 for illegal, ongoing or won */
{
int Color, Piece, PieceType, Victim, Xco, Yco, ToSquare, Ray, i;
Color = Board[0]*8 + 8; /* 8 or 16 */
if(Move[0] >= BRDSIZE || Move[1] >= BRDSIZE)
return(-1); /* invalid syntax */
Piece = Board[Move[0]+2];
if((Piece&24) != Color)
return(-1); /* no piece of us */
PieceType = Piece & 7; /* extract type */
for(i = Dir[PieceType]; Xvec[i]|Yvec[i]; i++)
{
Xco = Move[0]&7;
Yco = Move[0]&070;
do{
Xco += Xvec[i-1];
Yco += Yvec[i-1];
if(Xco&~7|Yco&~070) break; /* off board */
ToSquare = Xco|Yco;
Victim = Board[ToSquare+2];
if(Victim&Color) break; /* capt. own */
if(Piece <= 2 && (Victim != 0 && Xvec[i-1] == 0 ||
Victim == 0 && Xvec[i-1] != 0))
break; /* Bad Pawn mode */
if(ToSquare == Move[1]) /* move found */
{ /* perform move */
if(PieceType == 1 && Yco == 070 ||
PieceType == 2 && Yco == 0)
Piece = Color + QUEEN; /* Promote to Queen */
Board[ToSquare+2] = Piece;
Board[1]++; /* 30-move counter */
if(Victim || PieceType <= 2) Board[1] = 0;
if((Victim&7) == KING) return 1; /* King captured */
return 0; /* signal caller that move was legal */
}
Ray = Slider[PieceType];
if(Xvec[i] == 0 && (PieceType == 1 && Yco == 020 ||
PieceType == 2 && Yco == 050) )
Ray++; /* extend Pawn */
} while(Victim==0 && Ray);
}
return(-1); /* move not found among legal ones */
}
char Image[] = ".?+nbrqk?*?NBRQK.";
void PrintBoard(unsigned char *b)
{
int i, j, k;
printf("\n a b c d e f g h %s\n", b[0]?"B":" ");
for(i=7; i>=0; i--)
{
printf("%d ", i+1);
for(j=0; j<8; j++)
printf(" %c", Image[b[8*i+j+2]&15]);
printf(" %d\n", i+1);
}
printf(" a b c d e f g h %s\n", b[0]?" ":"W");
}
main()
{
int i, j, k;
FILE *f;
f = fopen("chessi.sav", "rb");
if(f==NULL) exit(0);
fread((void *) Prog, 12, 1, f);
fread((void *) Prog, sizeof (short int), PROGMEM, f);
fclose(f);
while(1)
{
IniBoard(Table, 0);
PrintBoard(Table);
i = Run(Prog, Table, BRDSIZE+2, 2, TLIMIT);
printf("time=%d, output = %o-%o (%c%c-%c%c)\n",
i, OutBuf[0], OutBuf[1],
'a'+(OutBuf[0]&7), '1'+(OutBuf[0]>>3&7),
'a'+(OutBuf[1]&7), '1'+(OutBuf[1]>>3&7) );
printf("Result = %d\n", j = LegalMove(Table, OutBuf));
if(j>=-10) getchar();
}
}