/***********************************************************************/ /* 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(); } }