diff options
| author | Hanjie Wu <hanjiew@andrew.cmu.edu> | 2023-04-18 02:21:10 -0400 |
|---|---|---|
| committer | Hanjie Wu <hanjiew@andrew.cmu.edu> | 2023-04-18 02:21:10 -0400 |
| commit | c71294cdd3581c3738d24ffd65414f8644a1094d (patch) | |
| tree | c86245d50fad9eee4163dbba169bd1839edbf88f /410user | |
initial commit
Diffstat (limited to '410user')
144 files changed, 17776 insertions, 0 deletions
diff --git a/410user/crt0.c b/410user/crt0.c new file mode 100644 index 0000000..abe8c50 --- /dev/null +++ b/410user/crt0.c @@ -0,0 +1,19 @@ +/* @file crt0.c + * @brief The 15-410 userland C runtime setup function + * + * @note The build infrastructure "knows" that _main is the entrypoint + * function and will do the right thing as a result. + */ + +#include <stdlib.h> +#include <syscall.h> +#include <assert.h> + +extern int main(int argc, char *argv[]); +extern void install_autostack(void * stack_high, void * stack_low); + +void _main(int argc, char *argv[], void *stack_high, void *stack_low) +{ + install_autostack(stack_high, stack_low); + exit(main(argc, argv)); +} diff --git a/410user/exec2obj.c b/410user/exec2obj.c new file mode 100644 index 0000000..80c1a57 --- /dev/null +++ b/410user/exec2obj.c @@ -0,0 +1,208 @@ +#include "410kern/inc/exec2obj.h" +#include <stdio.h> +#include <string.h> + +#define STABS 0 + +void print_usage() { + fprintf(stderr, "Usage: exec2obj <file>...\n"); + fprintf(stderr, "Creates a .s file containing a const char array for each file\n"); + fprintf(stderr, "given as an argument. Each array is initialized to the contents\n"); + fprintf(stderr, "of that file. A table of contents is also created. Look at\n"); + fprintf(stderr, "exec2obj.h for more information.\n\n"); +} + +char header[] = +#if STABS +"\t.file\t\"user_apps.c\"\n" +"\t.stabs\t\"/home/gghartma/15-410/proj2/\",100,0,0,.Ltext0\n" +"\t.stabs\t\"user_apps.c\",100,0,0,.Ltext0\n" +#endif +"\t.text\n" +".Ltext0:\n" +#if STABS +"\t.stabs\t\"gcc2_compiled.\",60,0,0,0\n" +"\t.stabs\t\"int:t(0,1)=r(0,1);-2147483648;2147483647;\",128,0,0,0\n" +"\t.stabs\t\"char:t(0,2)=r(0,2);0;127;\",128,0,0,0\n" +"\t.stabs\t\"long int:t(0,3)=r(0,3);-2147483648;2147483647;\",128,0,0,0\n" +"\t.stabs\t\"unsigned int:t(0,4)=r(0,4);0000000000000;0037777777777;\",128,0,0,0\n" +"\t.stabs\t\"long unsigned int:t(0,5)=r(0,5);0000000000000;0037777777777;\",128,0,0,0\n" +"\t.stabs\t\"long long int:t(0,6)=@s64;r(0,6);01000000000000000000000;0777777777777777777777;\",128,0,0,0\n" +"\t.stabs\t\"long long unsigned int:t(0,7)=@s64;r(0,7);0000000000000;01777777777777777777777;\",128,0,0,0\n" +"\t.stabs\t\"short int:t(0,8)=@s16;r(0,8);-32768;32767;\",128,0,0,0\n" +"\t.stabs\t\"short unsigned int:t(0,9)=@s16;r(0,9);0;65535;\",128,0,0,0\n" +"\t.stabs\t\"signed char:t(0,10)=@s8;r(0,10);-128;127;\",128,0,0,0\n" +"\t.stabs\t\"unsigned char:t(0,11)=@s8;r(0,11);0;255;\",128,0,0,0\n" +"\t.stabs\t\"float:t(0,12)=r(0,1);4;0;\",128,0,0,0\n" +"\t.stabs\t\"double:t(0,13)=r(0,1);8;0;\",128,0,0,0\n" +"\t.stabs\t\"long double:t(0,14)=r(0,1);12;0;\",128,0,0,0\n" +"\t.stabs\t\"complex int:t(0,15)=s8real:(0,1),0,32;imag:(0,1),32,32;;\",128,0,0,0\n" +"\t.stabs\t\"complex float:t(0,16)=R3;8;0;\",128,0,0,0\n" +"\t.stabs\t\"complex double:t(0,17)=R4;16;0;\",128,0,0,0\n" +"\t.stabs\t\"complex long double:t(0,18)=R5;24;0;\",128,0,0,0\n" +"\t.stabs\t\"void:t(0,19)=(0,19)\",128,0,0,0\n" +"\t.stabs\t\"__builtin_va_list:t(0,20)=*(0,2)\",128,0,0,0\n" +"\t.stabs\t\"_Bool:t(0,21)=@s8;-16\",128,0,0,0\n" +"\t.stabs\t\"user_apps.c\",130,0,0,0\n" +"\t.stabs\t\"410kern/lib/inc/exec2obj.h\",130,0,0,0\n" +"\t.stabs\t\"exec2obj_userapp_TOC_entry:t(2,1)=(2,2)=s264execname:(2,3)=ar(2,4)=r(2,4);0000000000000;0037777777777;;0;255;(2,5)=k(0,2),0,2048;execbytes:(2,6)=*(2,5),2048,32;execlen:(0,1),2080,32;;\",128,0,21,0\n" +"\t.stabn\t162,0,0,0\n" +#endif +"\t.section\t.rodata\n" + ; + +void emit_file_header(FILE *s, const char *file, int execsize) +{ + fprintf(s,".globl %s_exec2obj_userapp_code_ptr\n", file); + fprintf(s,"\t.align 32\n"); + fprintf(s,"\t.type\t%s_exec2obj_userapp_code_ptr, @object\n", file); + fprintf(s,"\t.size\t%s_exec2obj_userapp_code_ptr, %d\n", file, execsize); + fprintf(s,"%s_exec2obj_userapp_code_ptr:\n", file); +} + +int emit_file_bytes(FILE *out, FILE *in, int bytes) +{ + char line[1]; + static const size_t sz = sizeof(line) / sizeof(line[0]); + while (1) { + size_t rval = fread(line, sizeof(line[0]), sz, in); + if (rval <= 0) + break; + bytes -= rval; + fprintf(out, "\t.byte\t%d", line[0]); + char *it = line + 1; + char *end = line + rval; + while (it != end) { + fprintf(out, ",%d", *it++); + } + fprintf(out, "\n"); + } + return bytes; +} + +void emit_dir_header(FILE *out, int nrfiles) +{ + fprintf(out, ".globl exec2obj_userapp_count\n" + "\t.align 4\n" + "\t.type\texec2obj_userapp_count, @object\n" + "\t.size\texec2obj_userapp_count, 4\n" + "exec2obj_userapp_count:\n"); + fprintf(out, "\t.long\t%d\n", nrfiles); + fprintf(out, ".globl exec2obj_userapp_TOC\n" + "\t.align 32\n" + "\t.type\texec2obj_userapp_TOC, @object\n"); + fprintf(out, "\t.size\texec2obj_userapp_TOC, %d\n", sizeof(exec2obj_userapp_TOC)); + fprintf(out, "exec2obj_userapp_TOC:\n"); +} + +void emit_dir_entry(FILE *out, const char *name, int size) +{ + /* This is an awful hack, since we want the directory listing file + * named something that it can't be named on the host file system + * and can't appear in a symbol name. */ + const char *listed_name = + (strcmp(name, "__DIR_LISTING__") == 0) ? "." : name; + + fprintf(out, "\t.string\t\"%s\"\n", listed_name); + fprintf(out, "\t.zero\t%d\n", sizeof(exec2obj_userapp_TOC[0].execname) - strlen(listed_name) - 1); + fprintf(out, "\t.long\t%s_exec2obj_userapp_code_ptr\n", name); + fprintf(out, "\t.long\t%d\n", size); +} + + +void emit_dir_footer(FILE *out, int nrfiles) +{ + fprintf(out, "\t.zero\t%d\n", + sizeof(exec2obj_userapp_TOC) - nrfiles * sizeof(exec2obj_userapp_TOC[0])); + fprintf(out, +#if STABS + "\t.stabs\t\"exec2obj_userapp_count:G(1,1)=k(0,1)\",32,0,8,0\n" + "\t.stabs\t\"exec2obj_userapp_TOC:G(1,2)=ar(2,4);0;127;(1,3)=k(2,1)\",32,0,9,0\n" + "\t.stabs\t\"idle_exec2obj_userapp_code_ptr:G(1,4)=ar(2,4);0;9574;(2,5)\",32,0,2,0\n" + "\t.stabs\t\"shell_exec2obj_userapp_code_ptr:G(1,5)=ar(2,4);0;39418;(2,5)\",32,0,4,0\n" + "\t.stabs\t\"init_exec2obj_userapp_code_ptr:G(1,6)=ar(2,4);0;21722;(2,5)\",32,0,6,0\n" +#endif + "\t.text\n" +#if STABS + "\t.stabs \"\",100,0,0,.Letext\n" +#endif + ".Letext:\n" +#if STABS + "\t.section\t.note.GNU-stack,\"\",@progbits\n" + "\t.ident\t\"GCC: (GNU) 3.3.5 (Debian 1:3.3.5-13)\"\n" +#endif + ); +} + +#define MAX_FNAME 128 + +int main(int argc, char** argv) { + FILE *in; + int execsize = 0; + int file_iter = 1; + int execsizes[MAX_NUM_APP_ENTRIES]; + + char fname_buf[MAX_FNAME]; + + /* If there are no executables specified it's an error. */ + if (argc < 2) { + print_usage(); + return -1; + } + + if (argc > MAX_NUM_APP_ENTRIES + 1) { + fprintf(stderr, "Too many executables: The maximum is %d\n", MAX_NUM_APP_ENTRIES); + } + + fwrite(header, sizeof(header[0]), sizeof(header) / sizeof(header[0]) - 1, stdout); + + while (file_iter < argc) { + + strncpy(fname_buf, argv[file_iter], MAX_FNAME); + strncat(fname_buf, ".strip", MAX_FNAME - strlen(fname_buf)); + + in = fopen(fname_buf,"r"); + if (!in) { + fprintf(stderr, "Could not open %s for reading; falling back.\n",fname_buf); + + /* Open the executable. */ + in = fopen(argv[file_iter],"r"); + if (!in) { + fprintf(stderr, "Could not open %s for reading.\n",argv[file_iter]); + printf("\n\n.abort\n\n"); + return -1; + } + } + + /* Find size of executable. */ + fseek(in,0,SEEK_END); + execsize = ftell(in); + fseek(in,0,SEEK_SET); + + execsizes[file_iter] = execsize; + + + /* Output the header of the file. */ + + emit_file_header(stdout, argv[file_iter], execsize); + emit_file_bytes(stdout, in, execsize); + + fclose(in); + + /* Move on to the next file. */ + file_iter++; + } + + emit_dir_header(stdout, argc-1); + + /* Output the table of contents. */ + file_iter = 1; + + /* Output all other entries in TOC. */ + while(file_iter < argc) { + emit_dir_entry(stdout, argv[file_iter], execsizes[file_iter]); + file_iter++; + } + emit_dir_footer(stdout, argc-1); + return 0; +} diff --git a/410user/inc/410_tests.h b/410user/inc/410_tests.h new file mode 100644 index 0000000..01d0e95 --- /dev/null +++ b/410user/inc/410_tests.h @@ -0,0 +1,77 @@ +/* Test program for 15-410 project 3 Fall 2003 + * Tadashi Okoshi (slash) + */ + +#ifndef _410_TESTS_H_ +#define _410_TESTS_H_ + +#define TEST_START_CMPLT " START__TYPE_COMPLETE" +#define TEST_START_ABORT " START__TYPE_ABORT" +#define TEST_START_4EVER " START__TYPE_FOREVER" + /** An obsoleted progress detection mechanism. */ +#define TEST_START_4EVER_PROGRESS " START__TYPE_FOREVER_PROGRESS" + +#define TEST_END_SUCCESS " END__SUCCESS" +#define TEST_END_FAIL " END__FAIL" + +/*Don't change this for now. (slash)*/ +#define TEST_PFX "(^_^)_" + +#include <simics.h> /* lprintf() */ + +#ifndef ASSEMBLER + +#include <report.h> /* report_start(), etc. */ + +/* macros added by mtomczak */ +/* macro assumptions: + 1) static char test_name[] is defined (using DEF_TEST_NAME macro) + 2) In each function, REPORT_LOCAL_INIT called before REPORT_ON_ERR +*/ + +#define DEF_TEST_NAME(x) const char *test_name = x + +#define REPORT_START_CMPLT report_start(START_CMPLT) +#define REPORT_START_ABORT report_start(START_ABORT) +#define REPORT_START_4EVER report_start(START_4EVER) + +#define REPORT_END_SUCCESS report_end(END_SUCCESS) +#define REPORT_END_FAIL report_end(END_FAIL) + +#define REPORT_LOCAL_INIT +#define REPORT_MISC(x) report_misc(x) +#define REPORT_ERR(x,code) report_err(x, code) +#define REPORT_FAIL_ERR(x,code) report_fatal(x, code) +#define REPORT_ON_ERR(exp) report_on_err(#exp, __LINE__, exp) +#define REPORT_FAILOUT_ON_ERR(exp) fatal_on_err(#exp, __LINE__, exp) + +/**************************************************/ +/*memo*/ +/* + +//At the beginning of the test code. +lprintf("%s%s%s",TEST_PFX,test_name,TEST_START_CMPLT); + or +lprintf("%s%s%s",TEST_PFX,test_name,TEST_START_ABORT); + or +lprintf("%s%s%s",TEST_PFX,test_name,TEST_START_4EVER); + +//In the test body... +.... +lprintf("%s%s%s",TEST_PFX,test_name,"foo mesg."); +lprintf("%s%s%s",TEST_PFX,test_name,"bar mesg."); +.... + +//At the end of the test (only START_CMPLT case) +lprintf("%s%s%s",TEST_PFX,test_name,TEST_END_SUCCESS); + or +lprintf("%s%s%s",TEST_PFX,test_name,TEST_END_FAIL); + +*/ + +#define TEST_PROG_ENGAGE(i) sim_fr_prog(i) +#define TEST_PROG_PROGRESS sim_fr_here() + +#endif /* !ASSEMBLER */ + +#endif /* _410_TESTS_H_ */ diff --git a/410user/inc/asm_style.h b/410user/inc/asm_style.h new file mode 100644 index 0000000..6af13da --- /dev/null +++ b/410user/inc/asm_style.h @@ -0,0 +1,126 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +#ifndef _ASM_STYLE_H_ +#define _ASM_STYLE_H_ + +/* 15-410 */ +#ifndef HAVE_P2ALIGN +#define HAVE_P2ALIGN +#endif +#ifndef __ELF__ +#define __ELF__ +#endif +/* 15-410 */ + +/* This is a more reliable delay than a few short jmps. */ +#define IODELAY pushl %eax; inb $0x80,%al; inb $0x80,%al; popl %eax + +#define S_ARG0 4(%esp) +#define S_ARG1 8(%esp) +#define S_ARG2 12(%esp) +#define S_ARG3 16(%esp) + +#define FRAME pushl %ebp; movl %esp, %ebp +#define EMARF leave + +#define B_ARG0 8(%ebp) +#define B_ARG1 12(%ebp) +#define B_ARG2 16(%ebp) +#define B_ARG3 20(%ebp) + +#ifdef i486 +#define TEXT_ALIGN 4 +#else +#define TEXT_ALIGN 2 +#endif +#define DATA_ALIGN 2 +#define ALIGN TEXT_ALIGN + +/* + * The .align directive has different meaning on the x86 when using ELF + * than when using a.out. + * Newer GNU as remedies this problem by providing .p2align and .balign. + */ +#if defined(HAVE_P2ALIGN) +# define P2ALIGN(p2) .p2align p2 +#elif defined(__ELF__) +# define P2ALIGN(p2) .align (1<<(p2)) +#else +# define P2ALIGN(p2) .align p2 +#endif + +#define LCL(x) x + +#define LB(x,n) n +#ifndef __ELF__ +#define EXT(x) _ ## x +#define LEXT(x) _ ## x ## : +#define SEXT(x) "_"#x +#else +#define EXT(x) x +#define LEXT(x) x ## : +#define SEXT(x) #x +#endif +#define GLEXT(x) .globl EXT(x); LEXT(x) +#define LCLL(x) x ## : +#define gLB(n) n ## : +#define LBb(x,n) n ## b +#define LBf(x,n) n ## f + + +/* Symbol types */ +#ifdef __ELF__ +#define FUNCSYM(x) .type x,@function +#else +#define FUNCSYM(x) /* nothing */ +#endif + + +#ifdef GPROF + +#define MCOUNT .data; gLB(9) .long 0; .text; lea LBb(x, 9),%edx; call mcount +#define ENTRY(x) .globl EXT(x); P2ALIGN(TEXT_ALIGN); LEXT(x) ; \ + pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp; +#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \ + P2ALIGN(TEXT_ALIGN); LEXT(x) LEXT(y) +#define ASENTRY(x) .globl x; P2ALIGN(TEXT_ALIGN); gLB(x) ; \ + pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp; + +#else /* ndef GPROF */ + +#define MCOUNT +#define ENTRY(x) FUNCSYM(x); .globl EXT(x); P2ALIGN(TEXT_ALIGN); LEXT(x) +#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \ + P2ALIGN(TEXT_ALIGN); LEXT(x) LEXT(y) +#define ASENTRY(x) .globl x; P2ALIGN(TEXT_ALIGN); gLB(x) + +#endif /* ndef GPROF */ + + +#define Entry(x) P2ALIGN(TEXT_ALIGN); GLEXT(x) +#define DATA(x) P2ALIGN(DATA_ALIGN); GLEXT(x) + +#endif /* _ASM_STYLE_H_ */ diff --git a/410user/inc/assert.h b/410user/inc/assert.h new file mode 100644 index 0000000..0d989a8 --- /dev/null +++ b/410user/inc/assert.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + * + * Author: Bryan Ford, University of Utah CSL + */ +#ifndef _ASSERT_H_ +#define _ASSERT_H_ + +extern void panic(const char *format, ...); + +#ifndef NDEBUG +#define assert(expression) do { \ + if(!(expression)) { \ + panic("%s:%u: failed assertion `%s'", __FILE__, __LINE__, #expression);\ + } \ +} while(0) +#else +#define assert(expression) ((void)0) +#endif + +/* Extended for 15-410 at Carnegie Mellon. + * + * The following conditions are checked even if NDEBUG is defined: + * affirm(3 > 0); + * affirm_msg(3 > 0, "arithmetic broken around %d and %d", 3, 0); + * reject(0 > 3); + * reject_msg(0 > 3, "arithmetic broken around %d and %d", 0, 3); + */ + +#define affirm(expression) do { \ + if(!(expression)) { \ + panic("%s:%u: failed affirmation `%s'", \ + __FILE__, __LINE__, #expression); \ + } \ +} while(0) + +#define reject(expression) do { \ + if(expression) { \ + panic("%s:%u: rejecting result `%s'", __FILE__, __LINE__, #expression);\ + } \ +} while(0) + +#define affirm_msg(expression, ...) do { \ + if(!(expression)) { \ + panic(__VA_ARGS__); \ + } \ +} while(0) + +#define reject_msg(expression, ...) \ + affirm_msg(!(expression), __VA_ARGS__) + +#endif /* _ASSERT_H_ */ diff --git a/410user/inc/cond.h b/410user/inc/cond.h new file mode 100644 index 0000000..aa12609 --- /dev/null +++ b/410user/inc/cond.h @@ -0,0 +1,18 @@ +/** @file cond.h + * @brief This file defines the interface for condition variables. + */ + +#ifndef COND_H +#define COND_H + +#include <mutex.h> +#include <cond_type.h> + +/* condition variable functions */ +int cond_init( cond_t *cv ); +void cond_destroy( cond_t *cv ); +void cond_wait( cond_t *cv, mutex_t *mp ); +void cond_signal( cond_t *cv ); +void cond_broadcast( cond_t *cv ); + +#endif /* COND_H */ diff --git a/410user/inc/malloc.h b/410user/inc/malloc.h new file mode 100644 index 0000000..88827f6 --- /dev/null +++ b/410user/inc/malloc.h @@ -0,0 +1,17 @@ +#include <stdlib.h> +#include <types.h> + +#ifndef _MALLOC_WRAPPERS_H_ +#define _MALLOC_WRAPPERS_H_ + +void *malloc(size_t size); +void *calloc(size_t nelt, size_t eltsize); +void *realloc(void *buf, size_t new_size); +void free(void *buf); + +void *_malloc(size_t size); +void *_calloc(size_t nelt, size_t eltsize); +void *_realloc(void *buf, size_t new_size); +void _free(void *buf); + +#endif /* _MALLOC_WRAPPERS_H_ */ diff --git a/410user/inc/mutex.h b/410user/inc/mutex.h new file mode 100644 index 0000000..36ec0e1 --- /dev/null +++ b/410user/inc/mutex.h @@ -0,0 +1,15 @@ +/** @file mutex.h + * @brief This file defines the interface for mutexes. + */ + +#ifndef MUTEX_H +#define MUTEX_H + +#include <mutex_type.h> + +int mutex_init( mutex_t *mp ); +void mutex_destroy( mutex_t *mp ); +void mutex_lock( mutex_t *mp ); +void mutex_unlock( mutex_t *mp ); + +#endif /* MUTEX_H */ diff --git a/410user/inc/rand.h b/410user/inc/rand.h new file mode 100644 index 0000000..6c23819 --- /dev/null +++ b/410user/inc/rand.h @@ -0,0 +1,35 @@ +/* A C-program for MT19937: Integer version */ +/* genrand() generates one pseudorandom unsigned integer (32bit) */ +/* which is uniformly distributed among 0 to 2^32-1 for each */ +/* call. sgenrand(seed) set initial values to the working area */ +/* of 624 words. Before genrand(), sgenrand(seed) must be */ +/* called once. (seed is any 32-bit integer except for 0). */ +/* Coded by Takuji Nishimura, considering the suggestions by */ +/* Topher Cooper and Marc Rieffel in July-Aug. 1997. */ + +/* This library is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public */ +/* License as published by the Free Software Foundation; either */ +/* version 2 of the License, or (at your option) any later */ +/* version. */ +/* This library is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ +/* See the GNU Library General Public License for more details. */ +/* You should have received a copy of the GNU Library General */ +/* Public License along with this library; if not, write to the */ +/* Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA */ +/* 02111-1307 USA */ + +/* Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. */ +/* Any feedback is very welcome. For any question, comments, */ +/* see http://www.math.keio.ac.jp/matumoto/emt.html or email */ +/* matumoto@math.keio.ac.jp */ + +#ifndef _RAND_H +#define _RAND_H + +void sgenrand( unsigned long ); +unsigned long genrand( void ); + +#endif /* _RAND_H */ diff --git a/410user/inc/rwlock.h b/410user/inc/rwlock.h new file mode 100644 index 0000000..ad793f8 --- /dev/null +++ b/410user/inc/rwlock.h @@ -0,0 +1,20 @@ +/** @file rwlock.h + * @brief This file defines the interface to readers/writers locks + */ + +#ifndef RWLOCK_H +#define RWLOCK_H + +#define RWLOCK_READ 0 +#define RWLOCK_WRITE 1 + +#include <rwlock_type.h> + +/* readers/writers lock functions */ +int rwlock_init( rwlock_t *rwlock ); +void rwlock_lock( rwlock_t *rwlock, int type ); +void rwlock_unlock( rwlock_t *rwlock ); +void rwlock_destroy( rwlock_t *rwlock ); +void rwlock_downgrade( rwlock_t *rwlock); + +#endif /* RW_H */ diff --git a/410user/inc/sem.h b/410user/inc/sem.h new file mode 100644 index 0000000..8509042 --- /dev/null +++ b/410user/inc/sem.h @@ -0,0 +1,16 @@ +/** @file sem.h + * @brief This file defines the interface to semaphores + */ + +#ifndef SEM_H +#define SEM_H + +#include <sem_type.h> + +/* semaphore functions */ +int sem_init( sem_t *sem, int count ); +void sem_wait( sem_t *sem ); +void sem_signal( sem_t *sem ); +void sem_destroy( sem_t *sem ); + +#endif /* SEM_H */ diff --git a/410user/inc/stdarg.h b/410user/inc/stdarg.h new file mode 100644 index 0000000..ba9add0 --- /dev/null +++ b/410user/inc/stdarg.h @@ -0,0 +1,18 @@ +#ifndef _STDARG_H_ +#define _STDARG_H_ + +/* This is awful, but really these are compiler intrinsics, so we use the + * GNU compiler intrinsics. + */ + +#ifdef __GNUC__ +typedef __builtin_va_list va_list; +#define va_start(v,l) __builtin_va_start(v,l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v,l) __builtin_va_arg(v,l) +#define va_copy(d,s) __builtin_va_copy(d,s) +#else +#error "Don't know how to use varargs not on GNUC, sorry." +#endif + +#endif diff --git a/410user/inc/stdbool.h b/410user/inc/stdbool.h new file mode 100644 index 0000000..5060f36 --- /dev/null +++ b/410user/inc/stdbool.h @@ -0,0 +1,15 @@ +/** @file stdbool.h + * @author John Gallagher (gallaghe) + */ + +#ifndef _STDBOOL_H_ +#define _STDBOOL_H_ + +#define bool _Bool + +#define false 0 +#define true 1 + +#define __bool_true_false_are_defined 1 + +#endif /* _STDBOOL_H_ */ diff --git a/410user/inc/stddef.h b/410user/inc/stddef.h new file mode 100644 index 0000000..b321b53 --- /dev/null +++ b/410user/inc/stddef.h @@ -0,0 +1,12 @@ +#ifndef _STDDEF_H_ +#define _STDDEF_H_ + +#include <types.h> /* for size_t, ptrdiff_t */ + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define offsetof(stype,field) ((size_t)(&((stype*)NULL)->field)) + +#endif /* _STDDEF_H_ */ diff --git a/410user/inc/stdint.h b/410user/inc/stdint.h new file mode 100644 index 0000000..9bdf21c --- /dev/null +++ b/410user/inc/stdint.h @@ -0,0 +1,114 @@ +/** @file lib/stdint.h + * + * @brief Standard integer type definitions + * + * @bug The standard integer state of our library is a little questionable. + * I think types.h has become a dumping ground for things that don't fit well, + * and some of that should move here/be deleted. + * It's missing a few things that it probably should have (wchar, ptrdiff + * sizing), but I think it should be fine until students actually use those + * features. + * + * @author matthewj S2008 + @author Matt Bryant (mbryant) S'16 + */ + +#ifndef LIB_STDINT_H +#define LIB_STDINT_H + +#ifndef ASSEMBLER + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned long uint32_t; +typedef unsigned long long uint64_t; + +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed long int32_t; +typedef signed long long int64_t; + +typedef int intptr_t; +typedef unsigned int uintptr_t; + +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; + +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; + +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +#endif /* !ASSEMBLER */ + +#define UINT8_C(x) (x) +#define UINT16_C(x) (x) +#define UINT32_C(x) (x ## U) +#define UINT64_C(x) (x ## ULL) + +#define INT8_C(x) (x) +#define INT16_C(x) (x) +#define INT32_C(x) (x) +#define INT64_C(x) (x ## LL) + +#define INTMAX_C(x) (x ## LL) +#define UINTMAX_C(x) (x ## ULL) + +#define INT8_MIN (-128) +#define INT8_MAX (127) +#define INT16_MIN (-32768) +#define INT16_MAX (32767) +#define INT32_MIN (0x80000000) +#define INT32_MAX (0x7FFFFFFF) +#define INT64_MIN (0x8000000000000000LL) +#define INT64_MAX (0x7FFFFFFFFFFFFFFFLL) + +#define UINT8_MAX (255) +#define UINT16_MAX (65535) +#define UINT32_MAX (0xFFFFFFFF) +#define UINT64_MAX (0xFFFFFFFFFFFFFFFFULL) + +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX + +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX + +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +#endif /* !LIB_STDINT_H */ diff --git a/410user/inc/thread.h b/410user/inc/thread.h new file mode 100644 index 0000000..cd8358f --- /dev/null +++ b/410user/inc/thread.h @@ -0,0 +1,26 @@ +/** @file thread.h + * @brief This file defines thread-management interface. + * + * It should NOT contain any of the thread library internals. + * Therefore, you may NOT modify this file. + * + * However, you MAY modify user/libthread/thr_internals.h. + * + */ + + + +#ifndef THREAD_H +#define THREAD_H + +#include <thr_internals.h> + +/* thread library functions */ +int thr_init( unsigned int size ); +int thr_create( void *(*func)(void *), void *args ); +int thr_join( int tid, void **statusp ); +void thr_exit( void *status ); +int thr_getid( void ); +int thr_yield( int tid ); + +#endif /* THREAD_H */ diff --git a/410user/inc/types.h b/410user/inc/types.h new file mode 100644 index 0000000..eef2003 --- /dev/null +++ b/410user/inc/types.h @@ -0,0 +1,23 @@ +/** @file lib/types.h + * @brief Defines some C standard types as well as + * wrapper types for some of the imported FLUX library code. + * @author matthewj S2008 + */ + +#ifndef LIB_TYPES_H +#define LIB_TYPES_H + +typedef unsigned int size_t; +typedef unsigned long ptrdiff_t; + +/* WRAPPERS */ + +typedef unsigned long vm_offset_t; +typedef unsigned long vm_size_t; + +typedef enum { + FALSE = 0, + TRUE +} boolean_t; + +#endif /* !LIB_TYPES_H */ diff --git a/410user/libRNG/mt19937int.c b/410user/libRNG/mt19937int.c new file mode 100644 index 0000000..809bc01 --- /dev/null +++ b/410user/libRNG/mt19937int.c @@ -0,0 +1,97 @@ +/* A C-program for MT19937: Integer version */ +/* genrand() generates one pseudorandom unsigned integer (32bit) */ +/* which is uniformly distributed among 0 to 2^32-1 for each */ +/* call. sgenrand(seed) set initial values to the working area */ +/* of 624 words. Before genrand(), sgenrand(seed) must be */ +/* called once. (seed is any 32-bit integer except for 0). */ +/* Coded by Takuji Nishimura, considering the suggestions by */ +/* Topher Cooper and Marc Rieffel in July-Aug. 1997. */ + +/* This library is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public */ +/* License as published by the Free Software Foundation; either */ +/* version 2 of the License, or (at your option) any later */ +/* version. */ +/* This library is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ +/* See the GNU Library General Public License for more details. */ +/* You should have received a copy of the GNU Library General */ +/* Public License along with this library; if not, write to the */ +/* Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA */ +/* 02111-1307 USA */ + +/* Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. */ +/* Any feedback is very welcome. For any question, comments, */ +/* see http://www.math.keio.ac.jp/matumoto/emt.html or email */ +/* matumoto@math.keio.ac.jp */ + +/* modified for 15-410 at CMU by Zachary Anderson(zra) */ + +/* Period parameters */ +#define N 624 +#define M 397 +#define MATRIX_A 0x9908b0df /* constant vector a */ +#define UPPER_MASK 0x80000000 /* most significant w-r bits */ +#define LOWER_MASK 0x7fffffff /* least significant r bits */ + +/* Tempering parameters */ +#define TEMPERING_MASK_B 0x9d2c5680 +#define TEMPERING_MASK_C 0xefc60000 +#define TEMPERING_SHIFT_U(y) (y >> 11) +#define TEMPERING_SHIFT_S(y) (y << 7) +#define TEMPERING_SHIFT_T(y) (y << 15) +#define TEMPERING_SHIFT_L(y) (y >> 18) + +static unsigned long mt[N]; /* the array for the state vector */ +static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */ + +/* initializing the array with a NONZERO seed */ +void +sgenrand(seed) +unsigned long seed; +{ + /* setting initial seeds to mt[N] using */ + /* the generator Line 25 of Table 1 in */ + /* [KNUTH 1981, The Art of Computer Programming */ + /* Vol. 2 (2nd Ed.), pp102] */ + mt[0]= seed & 0xffffffff; + for (mti=1; mti<N; mti++) + mt[mti] = (69069 * mt[mti-1]) & 0xffffffff; +} + +unsigned long +genrand() +{ + unsigned long y; + static unsigned long mag01[2]={0x0, MATRIX_A}; + /* mag01[x] = x * MATRIX_A for x=0,1 */ + + if (mti >= N) { /* generate N words at one time */ + int kk; + + if (mti == N+1) /* if sgenrand() has not been called, */ + sgenrand(4357); /* a default initial seed is used */ + + for (kk=0;kk<N-M;kk++) { + y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); + mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1]; + } + for (;kk<N-1;kk++) { + y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); + mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1]; + } + y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); + mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1]; + + mti = 0; + } + + y = mt[mti++]; + y ^= TEMPERING_SHIFT_U(y); + y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B; + y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C; + y ^= TEMPERING_SHIFT_L(y); + + return y; +} diff --git a/410user/libRNG/user.mk b/410user/libRNG/user.mk new file mode 100644 index 0000000..29b2bb7 --- /dev/null +++ b/410user/libRNG/user.mk @@ -0,0 +1,6 @@ +410ULIB_RNG_OBJS = $(410UDIR)/libRNG/mt19937int.o + +ALL_410UOBJS += $(410ULIB_RNG_OBJS) +410UCLEANS += $(410UDIR)/libRNG.a + +$(410UDIR)/libRNG.a: $(410ULIB_RNG_OBJS) diff --git a/410user/libmalloc/malloc.c b/410user/libmalloc/malloc.c new file mode 100644 index 0000000..90bcf99 --- /dev/null +++ b/410user/libmalloc/malloc.c @@ -0,0 +1,639 @@ +/* + ****************************************************************************** + * mm-baseline.c * + * 64-bit struct-based implicit free list memory allocator * + * 15-213: Introduction to Computer Systems * + * * + * ************************************************************************ * + * DOCUMENTATION * + * * + * ** STRUCTURE. ** * + * * + * Both allocated and free blocks share the same header structure. * + * HEADER: 8-byte, aligned to 8th byte of an 16-byte aligned heap, where * + * - The lowest order bit is 1 when the block is allocated, and * + * 0 otherwise. * + * - The whole 8-byte value with the least significant bit set to 0 * + * represents the size of the block as a size_t * + * The size of a block includes the header and footer. * + * FOOTER: 8-byte, aligned to 0th byte of an 16-byte aligned heap. It * + * contains the exact copy of the block's header. * + * The minimum blocksize is 32 bytes. * + * * + * Allocated blocks contain the following: * + * HEADER, as defined above. * + * PAYLOAD: Memory allocated for program to store information. * + * FOOTER, as defined above. * + * The size of an allocated block is exactly PAYLOAD + HEADER + FOOTER. * + * * + * Free blocks contain the following: * + * HEADER, as defined above. * + * FOOTER, as defined above. * + * The size of an unallocated block is at least 32 bytes. * + * * + * Block Visualization. * + * block block+8 block+size-8 block+size * + * Allocated blocks: | HEADER | ... PAYLOAD ... | FOOTER | * + * * + * block block+8 block+size-8 block+size * + * Unallocated blocks: | HEADER | ... (empty) ... | FOOTER | * + * * + * ************************************************************************ * + * ** INITIALIZATION. ** * + * * + * The following visualization reflects the beginning of the heap. * + * start start+8 start+16 * + * INIT: | PROLOGUE_FOOTER | EPILOGUE_HEADER | * + * PROLOGUE_FOOTER: 8-byte footer, as defined above, that simulates the * + * end of an allocated block. Also serves as padding. * + * EPILOGUE_HEADER: 8-byte block indicating the end of the heap. * + * It simulates the beginning of an allocated block * + * The epilogue header is moved when the heap is extended. * + * * + * ************************************************************************ * + * ** BLOCK ALLOCATION. ** * + * * + * Upon memory request of size S, a block of size S + dsize, rounded up to * + * 16 bytes, is allocated on the heap, where dsize is 2*8 = 16. * + * Selecting the block for allocation is performed by finding the first * + * block that can fit the content based on a first-fit or next-fit search * + * policy. * + * The search starts from the beginning of the heap pointed by heap_listp. * + * It sequentially goes through each block in the implicit free list, * + * the end of the heap, until either * + * - A sufficiently-large unallocated block is found, or * + * - The end of the implicit free list is reached, which occurs * + * when no sufficiently-large unallocated block is available. * + * In case that a sufficiently-large unallocated block is found, then * + * that block will be used for allocation. Otherwise--that is, when no * + * sufficiently-large unallocated block is found--then more unallocated * + * memory of size chunksize or requested size, whichever is larger, is * + * requested through mem_sbrk, and the search is redone. * + * * + * ************************************************************************ * + * ** ADVICE FOR STUDENTS. ** * + * Step 0: Please read the writeup! * + * Write your heap checker. Write your heap checker. Write. Heap. checker. * + * Good luck, and have fun! * + * * + ****************************************************************************** + */ + +/* Do not change the following! */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdbool.h> +#include <stddef.h> + +#undef NDEBUG // the assert()s in this particular implementation are all O(1) and vital +#include <assert.h> + +#include "memlib.h" + +#define dbg_requires(...) assert(__VA_ARGS__) +#define dbg_assert(...) assert(__VA_ARGS__) +#define dbg_ensures(...) assert(__VA_ARGS__) + +/* Basic constants */ +typedef uint64_t word_t; +static const size_t wsize = sizeof(word_t); // word and header size (bytes) +static const size_t dsize = 2*sizeof(word_t); // double word size (bytes) +static const size_t min_block_size = 4*sizeof(word_t); // Minimum block size +static const size_t chunksize = (1 << 12); // requires (chunksize % 16 == 0) + +static const word_t alloc_mask = 0x1; +static const word_t size_mask = ~(word_t)0xF; + +typedef struct block +{ + /* Header contains size + allocation flag */ + word_t header; + /* + * We don't know how big the payload will be. Declaring it as an + * array of size 0 allows computing its starting address using + * pointer notation. + */ + char payload[0]; + /* + * We can't declare the footer as part of the struct, since its starting + * position is unknown + */ +} block_t; + + +/* Global variables */ +/* Pointer to first block */ +static block_t *heap_listp = NULL; + +/* Function prototypes for internal helper routines */ +static block_t *extend_heap(size_t size); +static void place(block_t *block, size_t asize); +static block_t *find_fit(size_t asize); +static block_t *coalesce(block_t *block); + +static size_t max(size_t x, size_t y); +static size_t round_up(size_t size, size_t n); +static word_t pack(size_t size, bool alloc); + +static size_t extract_size(word_t header); +static size_t get_size(block_t *block); +static size_t get_payload_size(block_t *block); + +static bool extract_alloc(word_t header); +static bool get_alloc(block_t *block); + +static void write_header(block_t *block, size_t size, bool alloc); +static void write_footer(block_t *block, size_t size, bool alloc); + +static block_t *payload_to_header(void *bp); +static void *header_to_payload(block_t *block); + +static block_t *find_next(block_t *block); +static word_t *find_prev_footer(block_t *block); +static block_t *find_prev(block_t *block); + +bool mm_checkheap(int lineno); + +/* + * mm_init: initializes the heap; it is run once when heap_start == NULL. + * prior to any extend_heap operation, this is the heap: + * start start+8 start+16 + * INIT: | PROLOGUE_FOOTER | EPILOGUE_HEADER | + * heap_listp ends up pointing to the epilogue header. + */ +bool mm_init(void) +{ + mem_init(0xffffffff); + + // Create the initial empty heap + word_t *start = (word_t *)(mem_sbrk(2*wsize)); + + if (start == NULL) + { + return false; + } + + start[0] = pack(0, true); // Prologue footer + start[1] = pack(0, true); // Epilogue header + // Heap starts with first block header (epilogue) + heap_listp = (block_t *) &(start[1]); + + // Extend the empty heap with a free block of chunksize bytes + if (extend_heap(chunksize) == NULL) + { + return false; + } + return true; +} + +/* + * malloc: allocates a block with size at least (size + dsize), rounded up to + * the nearest 16 bytes, with a minimum of 2*dsize. Seeks a + * sufficiently-large unallocated block on the heap to be allocated. + * If no such block is found, extends heap by the maximum between + * chunksize and (size + dsize) rounded up to the nearest 16 bytes, + * and then attempts to allocate all, or a part of, that memory. + * Returns NULL on failure, otherwise returns a pointer to such block. + * The allocated block will not be used for further allocations until + * freed. + */ +void *_malloc(size_t size) +{ + dbg_requires(mm_checkheap(__LINE__)); + + size_t asize; // Adjusted block size + size_t extendsize; // Amount to extend heap if no fit is found + block_t *block; + void *bp = NULL; + + if (heap_listp == NULL) // Initialize heap if it isn't initialized + { + mm_init(); + } + + if (size == 0) // Ignore spurious request + { + dbg_ensures(mm_checkheap(__LINE__)); + return bp; + } + + // Adjust block size to include overhead and to meet alignment requirements + asize = round_up(size, dsize) + dsize; + + // Search the free list for a fit + block = find_fit(asize); + + // If no fit is found, request more memory, and then and place the block + if (block == NULL) + { + extendsize = max(asize, chunksize); + block = extend_heap(extendsize); + if (block == NULL) // extend_heap returns an error + { + return bp; + } + + } + + place(block, asize); + bp = header_to_payload(block); + + dbg_ensures(mm_checkheap(__LINE__)); + return bp; +} + +/* + * free: Frees the block such that it is no longer allocated while still + * maintaining its size. Block will be available for use on malloc. + */ +void _free(void *bp) +{ + if (bp == NULL) + { + return; + } + + block_t *block = payload_to_header(bp); + size_t size = get_size(block); + + write_header(block, size, false); + write_footer(block, size, false); + + coalesce(block); + +} + +/* + * realloc: returns a pointer to an allocated region of at least size bytes: + * if ptrv is NULL, then call malloc(size); + * if size == 0, then call free(ptr) and returns NULL; + * else allocates new region of memory, copies old data to new memory, + * and then free old block. Returns old block if realloc fails or + * returns new pointer on success. + */ +void *_realloc(void *ptr, size_t size) +{ + block_t *block = payload_to_header(ptr); + size_t copysize; + void *newptr; + + // If size == 0, then free block and return NULL + if (size == 0) + { + _free(ptr); + return NULL; + } + + // If ptr is NULL, then equivalent to malloc + if (ptr == NULL) + { + return _malloc(size); + } + + // Otherwise, proceed with reallocation + newptr = _malloc(size); + // If malloc fails, the original block is left untouched + if (!newptr) + { + return NULL; + } + + // Copy the old data + copysize = get_payload_size(block); // gets size of old payload + if(size < copysize) + { + copysize = size; + } + memcpy(newptr, ptr, copysize); + + // Free the old block + _free(ptr); + + return newptr; +} + +/* + * calloc: Allocates a block with size at least (elements * size + dsize) + * through malloc, then initializes all bits in allocated memory to 0. + * Returns NULL on failure. + */ +void *_calloc(size_t nmemb, size_t size) +{ + void *bp; + size_t asize = nmemb * size; + + if (asize/nmemb != size) + // Multiplication overflowed + return NULL; + + bp = _malloc(asize); + if (bp == NULL) + { + return NULL; + } + // Initialize all bits to 0 + memset(bp, 0, asize); + + return bp; +} + +/******** The remaining content below are helper and debug routines ********/ + +/* + * extend_heap: Extends the heap with the requested number of bytes, and + * recreates epilogue header. Returns a pointer to the result of + * coalescing the newly-created block with previous free block, if + * applicable, or NULL in failure. + */ +static block_t *extend_heap(size_t size) +{ + void *bp; + + // Allocate an even number of words to maintain alignment + size = round_up(size, dsize); + if ((bp = mem_sbrk(size)) == NULL) + { + return NULL; + } + + // Initialize free block header/footer + block_t *block = payload_to_header(bp); + write_header(block, size, false); + write_footer(block, size, false); + // Create new epilogue header + block_t *block_next = find_next(block); + write_header(block_next, 0, true); + + // Coalesce in case the previous block was free + return coalesce(block); +} + +/* Coalesce: Coalesces current block with previous and next blocks if either + * or both are unallocated; otherwise the block is not modified. + * Returns pointer to the coalesced block. After coalescing, the + * immediate contiguous previous and next blocks must be allocated. + */ +static block_t *coalesce(block_t * block) +{ + block_t *block_next = find_next(block); + block_t *block_prev = find_prev(block); + + bool prev_alloc = extract_alloc(*(find_prev_footer(block))); + bool next_alloc = get_alloc(block_next); + size_t size = get_size(block); + + if (prev_alloc && next_alloc) // Case 1 + { + return block; + } + + else if (prev_alloc && !next_alloc) // Case 2 + { + size += get_size(block_next); + write_header(block, size, false); + write_footer(block, size, false); + } + + else if (!prev_alloc && next_alloc) // Case 3 + { + size += get_size(block_prev); + write_header(block_prev, size, false); + write_footer(block_prev, size, false); + block = block_prev; + } + + else // Case 4 + { + size += get_size(block_next) + get_size(block_prev); + write_header(block_prev, size, false); + write_footer(block_prev, size, false); + + block = block_prev; + } + return block; +} + +/* + * place: Places block with size of asize at the start of bp. If the remaining + * size is at least the minimum block size, then split the block to the + * the allocated block and the remaining block as free, which is then + * inserted into the segregated list. Requires that the block is + * initially unallocated. + */ +static void place(block_t *block, size_t asize) +{ + size_t csize = get_size(block); + + if ((csize - asize) >= min_block_size) + { + block_t *block_next; + write_header(block, asize, true); + write_footer(block, asize, true); + + block_next = find_next(block); + write_header(block_next, csize-asize, false); + write_footer(block_next, csize-asize, false); + } + + else + { + write_header(block, csize, true); + write_footer(block, csize, true); + } +} + +/* + * find_fit: Looks for a free block with at least asize bytes with + * first-fit policy. Returns NULL if none is found. + */ +static block_t *find_fit(size_t asize) +{ + block_t *block; + + for (block = heap_listp; get_size(block) > 0; + block = find_next(block)) + { + + if (!(get_alloc(block)) && (asize <= get_size(block))) + { + return block; + } + } + return NULL; // no fit found +} + +/* + * max: returns x if x > y, and y otherwise. + */ +static size_t max(size_t x, size_t y) +{ + return (x > y) ? x : y; +} + + +/* + * round_up: Rounds size up to next multiple of n + */ +static size_t round_up(size_t size, size_t n) +{ + return (n * ((size + (n-1)) / n)); +} + +/* + * pack: returns a header reflecting a specified size and its alloc status. + * If the block is allocated, the lowest bit is set to 1, and 0 otherwise. + */ +static word_t pack(size_t size, bool alloc) +{ + return alloc ? (size | 1) : size; +} + + +/* + * extract_size: returns the size of a given header value based on the header + * specification above. + */ +static size_t extract_size(word_t word) +{ + return (word & size_mask); +} + +/* + * get_size: returns the size of a given block by clearing the lowest 4 bits + * (as the heap is 16-byte aligned). + */ +static size_t get_size(block_t *block) +{ + return extract_size(block->header); +} + +/* + * get_payload_size: returns the payload size of a given block, equal to + * the entire block size minus the header and footer sizes. + */ +static size_t get_payload_size(block_t *block) +{ + size_t asize = get_size(block); + return asize - dsize; +} + +/* + * extract_alloc: returns the allocation status of a given header value based + * on the header specification above. + */ +static bool extract_alloc(word_t word) +{ + return (bool)(word & alloc_mask); +} + +/* + * get_alloc: returns true when the block is allocated based on the + * block header's lowest bit, and false otherwise. + */ +static bool get_alloc(block_t *block) +{ + return extract_alloc(block->header); +} + +/* + * write_header: given a block and its size and allocation status, + * writes an appropriate value to the block header. + */ +static void write_header(block_t *block, size_t size, bool alloc) +{ + block->header = pack(size, alloc); +} + + +/* + * write_footer: given a block and its size and allocation status, + * writes an appropriate value to the block footer by first + * computing the position of the footer. + */ +static void write_footer(block_t *block, size_t size, bool alloc) +{ + word_t *footerp = (word_t *)((block->payload) + get_size(block) - dsize); + *footerp = pack(size, alloc); +} + + +/* + * find_next: returns the next consecutive block on the heap by adding the + * size of the block. + */ +static block_t *find_next(block_t *block) +{ + dbg_requires(block != NULL); + block_t *block_next = (block_t *)(((char *)block) + get_size(block)); + + dbg_ensures(block_next != NULL); + return block_next; +} + +/* + * find_prev_footer: returns the footer of the previous block. + */ +static word_t *find_prev_footer(block_t *block) +{ + // Compute previous footer position as one word before the header + return (&(block->header)) - 1; +} + +/* + * find_prev: returns the previous block position by checking the previous + * block's footer and calculating the start of the previous block + * based on its size. + */ +static block_t *find_prev(block_t *block) +{ + word_t *footerp = find_prev_footer(block); + size_t size = extract_size(*footerp); + return (block_t *)((char *)block - size); +} + +/* + * payload_to_header: given a payload pointer, returns a pointer to the + * corresponding block. + */ +static block_t *payload_to_header(void *bp) +{ + return (block_t *)(((char *)bp) - offsetof(block_t, payload)); +} + +/* + * header_to_payload: given a block pointer, returns a pointer to the + * corresponding payload. + */ +static void *header_to_payload(block_t *block) +{ + return (void *)(block->payload); +} + +/* mm_checkheap: checks the heap for correctness; returns true if + * the heap is correct, and false otherwise. + * can call this function using mm_checkheap(__LINE__); + * to identify the line number of the call site. + */ +bool mm_checkheap(int lineno) +{ + (void)lineno; + if (heap_listp != NULL) + { + // check prologue footer: size is 0 and prologue is allocated + word_t prologue_footer = *find_prev_footer(heap_listp); + assert(extract_size(prologue_footer) == 0 && extract_alloc(prologue_footer)); + + // check header-footer consistency + block_t *block = heap_listp; + if (get_size(block) != 0) + { + word_t block_header = block->header; + word_t block_footer = *(find_prev_footer(find_next(heap_listp))); + assert(extract_size(block_header) == extract_size(block_footer)); + assert(extract_alloc(block_header) == extract_alloc(block_footer)); + } + } + return true; +} diff --git a/410user/libmalloc/memlib.c b/410user/libmalloc/memlib.c new file mode 100644 index 0000000..8332559 --- /dev/null +++ b/410user/libmalloc/memlib.c @@ -0,0 +1,72 @@ +/* This should look a lot like 15-213 support code. + * Guess what... + */ + +/* memlib.c - functions for modeling the memory system */ +/* $begin memlib */ + +#include <stddef.h> +#include <stdio.h> +#include <syscall.h> + +/* #define PAGE_SIZE 0x00001000 */ +/* #define PAGE_ALIGN_MASK 0xFFFFF000 */ +#define PAGE_ALIGN_MASK ((unsigned int) ~((unsigned int) (PAGE_SIZE-1))) + +#ifndef NULL +#define NULL 0 +#endif + +/* private global variables */ +static char *mem_max_addr; /* max virtual address for the heap */ +static char *mem_brkp; /* Simulated brk pointer */ +static char *mem_alloctop; /* Maximum allocated address */ + +extern void *_end; /* The end of the ELF binary address space */ + +/* + * mem_init - initializes the memory system model + */ +void mem_init(int max_heap_addr) +{ + /* The max address for the heap. */ + mem_max_addr = (char*)max_heap_addr; + mem_brkp = (char*)&_end + PAGE_SIZE; + mem_brkp = (char*)((int)mem_brkp & PAGE_ALIGN_MASK); + while (new_pages(mem_brkp, PAGE_SIZE)) + mem_brkp += PAGE_SIZE; + mem_alloctop = mem_brkp + PAGE_SIZE; +} + +/* + * mem_sbrk - simply uses the the sbrk function. Extends the heap + * by incr bytes and returns the start address of the new area. In + * this model, the heap cannot be shrunk. + */ +void *mem_sbrk(int incr) +{ + char *old_brk = mem_brkp; + + /* Error check the request. */ + if ( (incr < 0) || ((old_brk + incr) > mem_max_addr)) { + return (void *)NULL; + } + + if (old_brk + incr > mem_alloctop) { + int allocincr = old_brk + incr - mem_alloctop; + allocincr += PAGE_SIZE - 1; + allocincr &= PAGE_ALIGN_MASK; + + /* Issue a SBRK for more memory. */ + if (new_pages((void*)mem_alloctop, allocincr)) { + return (void *)NULL; + } + + mem_alloctop += allocincr; + } + + mem_brkp += incr; + + return (void *)old_brk; +} +/* $end memlib */ diff --git a/410user/libmalloc/memlib.h b/410user/libmalloc/memlib.h new file mode 100644 index 0000000..b4b8a62 --- /dev/null +++ b/410user/libmalloc/memlib.h @@ -0,0 +1,13 @@ +/* + * memlib.h + * Modified for use in 15-410 at CMU + * Zachary Anderson(zra) + */ + +#ifndef _MEMLIB_H +#define _MEMLIB_H + +void *mem_init(int size); +void *mem_sbrk(int incr); + +#endif /* _MEMLIB_H */ diff --git a/410user/libmalloc/user.mk b/410user/libmalloc/user.mk new file mode 100644 index 0000000..1e92daa --- /dev/null +++ b/410user/libmalloc/user.mk @@ -0,0 +1,7 @@ +410U_MALLOC_OBJS := malloc.o memlib.o +410U_MALLOC_OBJS := $(410U_MALLOC_OBJS:%=$(410UDIR)/libmalloc/%) + +ALL_410UOBJS += $(410U_MALLOC_OBJS) +410UCLEANS += $(410UDIR)/libmalloc.a + +$(410UDIR)/libmalloc.a: $(410U_MALLOC_OBJS) diff --git a/410user/libsimics/simics.S b/410user/libsimics/simics.S new file mode 100644 index 0000000..28c35dc --- /dev/null +++ b/410user/libsimics/simics.S @@ -0,0 +1,14 @@ +/* simics.S - Simics interface (user side) */ +/* Copyright (c) 2014 Carnegie Mellon University */ + +/* sim_call(ebx, ecx, edx) */ +.global sim_call +sim_call: + push %ebx + mov 0x8(%esp), %ebx + mov 0xC(%esp), %ecx + mov 0x10(%esp), %edx + mov $0, %eax + xchg %ebx, %ebx + pop %ebx + ret diff --git a/410user/libsimics/simics.h b/410user/libsimics/simics.h new file mode 100644 index 0000000..f865d5a --- /dev/null +++ b/410user/libsimics/simics.h @@ -0,0 +1,84 @@ +/** @file lib/simics.h + * @brief Simics interface (kernel side) + * @author matthewj S2008 + */ + +#ifndef LIB_SIMICS_H +#define LIB_SIMICS_H + +#ifdef ASSEMBLER +#define lprintf sim_printf +#endif + +#define SIM_IN_SIMICS 0x04100000 +#define SIM_MEMSIZE 0x04100001 +#define SIM_PUTS 0x04100002 +#define SIM_BREAKPOINT 0x04100003 +#define SIM_HALT 0x04100004 + +#define SIM_CK1 0x04108000 +#define SIM_FR_INKEYS 0x04108004 +#define SIM_FR_PROG 0x04108006 +#define SIM_FR_HERE 0x04108007 + +#define SIM_TEST_REPORT 0x0410800B + +#ifdef ASSEMBLER + +/* Now *this* is a fun macro. It expands into a simics call to 'num' with + * arguments 'arg0' and 'arg1'. For use in assembly functions, to call simics + * without touching the stack. */ + +#define INLINE_SIMCALL(num, arg0, arg1) \ + mov $num, %ebx; \ + mov arg0, %ecx; \ + mov arg1, %edx; \ + xchg %ebx, %ebx; + +#endif + +#ifndef ASSEMBLER + +#include <stdarg.h> + +/** @brief Calls simics. Arguments are ebx, ecx, edx. */ +extern int sim_call(int ebx, ...); + +/** @brief Returns whether we are in simics */ +extern int sim_in_simics(void); + +/** @brief Returns machine memory size, from simics */ +extern int sim_memsize(void); + +/** @brief Prints a string to the simics console */ +extern void sim_puts(const char *arg); + +/** @brief Breakpoint */ +extern void sim_breakpoint(void); + +/** @brief Halt the simulation */ +extern void sim_halt(void); + +/** @brief Run the checkpoint 1 checker. */ +extern void sim_ck1(void); + +/** @brief Grading harness stuff */ +extern void sim_fr_prog(int a); +extern void sim_fr_here(void); + +/** @brief Convenience wrappers around sim_puts(). */ +extern void sim_vprintf(const char* fmt, va_list ap); +extern void sim_printf(const char *fmt, ...) __attribute__((__format__ (__printf__, 1, 2))); + +/** @brief readline(), but wrapped in "magic" */ +int magic_readline(int size, char *buf); + +void sim_update_scoreboard(char *testname, int success); + +/* "Compatibility mode" for old code */ +#define MAGIC_BREAK sim_breakpoint() +#define lprintf(...) sim_printf(__VA_ARGS__) + +#endif /* !ASSEMBLER */ + +#endif /* !LIB_SIMICS_H */ diff --git a/410user/libsimics/simics_c.c b/410user/libsimics/simics_c.c new file mode 100644 index 0000000..c32a298 --- /dev/null +++ b/410user/libsimics/simics_c.c @@ -0,0 +1,61 @@ +#include <simics.h> +#include <stdarg.h> +#include <stdio.h> +#include <syscall.h> /* for readline() */ + +int sim_in_simics(void) { + return sim_call(SIM_IN_SIMICS); +} + +int sim_memsize(void) { + return sim_call(SIM_MEMSIZE); +} + +void sim_puts(const char *arg) { + sim_call(SIM_PUTS, arg); +} + +void sim_breakpoint(void) { + sim_call(SIM_BREAKPOINT); +} + +void sim_halt(void) { + sim_call(SIM_HALT); +} + +void sim_ck1(void) { + sim_call(SIM_CK1); +} + +void sim_fr_prog(int a) { + sim_call(SIM_FR_PROG, a); +} + +void sim_fr_here(void) { + sim_call(SIM_FR_HERE); +} + +void sim_vprintf(const char* fmt, va_list ap) +{ + char str[256]; + vsnprintf(str, sizeof(str) - 1, fmt, ap); + sim_puts(str); +} + +void sim_printf(const char* fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + sim_vprintf(fmt, ap); + va_end(ap); +} + +void sim_update_scoreboard(char *testname, int success) { + sim_call(SIM_TEST_REPORT, testname, success); +} + +int magic_readline(int size, char *buf) { + sim_call(SIM_FR_INKEYS); + return readline(size, buf); +} diff --git a/410user/libsimics/user.mk b/410user/libsimics/user.mk new file mode 100644 index 0000000..a31bbaf --- /dev/null +++ b/410user/libsimics/user.mk @@ -0,0 +1,10 @@ +410U_SIMICS_OBJS := \ + simics.o \ + simics_c.o + +410U_SIMICS_OBJS := $(410U_SIMICS_OBJS:%=$(410UDIR)/libsimics/%) + +ALL_410UOBJS += $(410U_SIMICS_OBJS) +410UCLEANS += $(410UDIR)/libsimics.a + +$(410UDIR)/libsimics.a: $(410U_SIMICS_OBJS) diff --git a/410user/libstdio/doprnt.c b/410user/libstdio/doprnt.c new file mode 100644 index 0000000..548e626 --- /dev/null +++ b/410user/libstdio/doprnt.c @@ -0,0 +1,646 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#include <stdarg.h> +#include <string.h> +#include <types.h> +#include "doprnt.h" + +/* + * Common code for printf et al. + * + * The calling routine typically takes a variable number of arguments, + * and passes the address of the first one. This implementation + * assumes a straightforward, stack implementation, aligned to the + * machine's wordsize. Increasing addresses are assumed to point to + * successive arguments (left-to-right), as is the case for a machine + * with a downward-growing stack with arguments pushed right-to-left. + * + * To write, for example, fprintf() using this routine, the code + * + * fprintf(fd, format, args) + * FILE *fd; + * char *format; + * { + * _doprnt(format, &args, fd); + * } + * + * would suffice. (This example does not handle the fprintf's "return + * value" correctly, but who looks at the return value of fprintf + * anyway?) + * + * This version implements the following printf features: + * + * %d decimal conversion + * %u unsigned conversion + * %x hexadecimal conversion + * %X hexadecimal conversion with capital letters + * %o octal conversion + * %c character + * %s string + * %m.n field width, precision + * %-m.n left adjustment + * %0m.n zero-padding + * %*.* width and precision taken from arguments + * + * This version does not implement %f, %e, or %g. It accepts, but + * ignores, an `l' as in %ld, %lo, %lx, and %lu, and therefore will not + * work correctly on machines for which sizeof(long) != sizeof(int). + * It does not even parse %D, %O, or %U; you should be using %ld, %o and + * %lu if you mean long conversion. + * + * As mentioned, this version does not return any reasonable value. + * + * Permission is granted to use, modify, or propagate this code as + * long as this notice is incorporated. + * + * Steve Summit 3/25/87 + */ + +/* + * Added formats for decoding device registers: + * + * printf("reg = %b", regval, "<base><arg>*") + * + * where <base> is the output base expressed as a control character: + * i.e. '\10' gives octal, '\20' gives hex. Each <arg> is a sequence of + * characters, the first of which gives the bit number to be inspected + * (origin 1), and the rest (up to a control character (<= 32)) give the + * name of the register. Thus + * printf("reg = %b\n", 3, "\10\2BITTWO\1BITONE") + * would produce + * reg = 3<BITTWO,BITONE> + * + * If the second character in <arg> is also a control character, it + * indicates the last bit of a bit field. In this case, printf will extract + * bits <1> to <2> and print it. Characters following the second control + * character are printed before the bit field. + * printf("reg = %b\n", 0xb, "\10\4\3FIELD1=\2BITTWO\1BITONE") + * would produce + * reg = b<FIELD1=2,BITONE> + */ +/* + * Added for general use: + * # prefix for alternate format: + * 0x (0X) for hex + * leading 0 for octal + * + print '+' if positive + * blank print ' ' if positive + * + * z signed hexadecimal + * r signed, 'radix' + * n unsigned, 'radix' + * + * D,U,O,Z same as corresponding lower-case versions + * (compatibility) + */ +/* + * Added ANSI %p for pointers. Output looks like 0x%08x. + */ +/* + * + * Added special for L4-use: %t format + * + * prints L4-threadids. standard format is "task.thread". Field-width + * may be specified with width-modifier. Padding begins with threadid, + * up to 2 chars, task-part follows. + * + * modifiers: + * # surrounds output with square brackets [] + * l prints the high and low part of a threadid + * fixed length for the dwords: 8 chars + * 0 as usual, padding after optional '[' + * - as usual + * + * Jork Loeser 9/20/99 + */ + +#define isdigit(d) ((d) >= '0' && (d) <= '9') +#define Ctod(c) ((c) - '0') + +#define MAXBUF (sizeof(long int) * 8) /* enough for binary */ + +static char digs[] = "0123456789abcdef"; + +static void +printnum(u, base, putc, putc_arg) + register unsigned long u; /* number to print */ + register int base; + void (*putc)(); + char *putc_arg; +{ + char buf[MAXBUF]; /* build number here */ + register char * p = &buf[MAXBUF-1]; + + do { + *p-- = digs[u % base]; + u /= base; + } while (u != 0); + + while (++p != &buf[MAXBUF]) + (*putc)(putc_arg, *p); +} + +static void +printnum_16(u, putc, putc_arg) + register unsigned long u; /* number to print */ + void (*putc)(); + char *putc_arg; +{ + char buf[8]; /* build number here */ + register char * p = &buf[7]; + int i; + + for(i=0; i<8;i++){ + *p-- = digs[u & 0x0f]; + u >>= 4; + }; + + for(i=0;i<8;i++){ + (*putc)(putc_arg, buf[i]); + } +} + +boolean_t _doprnt_truncates = FALSE; + +void _doprnt(fmt, args, radix, putc, putc_arg) + register const char *fmt; + va_list args; + int radix; /* default radix - for '%r' */ + void (*putc)(); /* character output */ + char *putc_arg; /* argument for putc */ +{ + int length; + int prec; + boolean_t ladjust; + char padc; + long long n, m; + unsigned long long u; + int plus_sign; + int sign_char; + boolean_t altfmt, truncate, upcase; + int base; + char c; + int longopt; + + while (*fmt != '\0') { + if (*fmt != '%') { + (*putc)(putc_arg, *fmt++); + continue; + } + + fmt++; + + length = 0; + prec = -1; + ladjust = FALSE; + padc = ' '; + plus_sign = 0; + sign_char = 0; + altfmt = FALSE; + longopt = 0; + + while (TRUE) { + if (*fmt == '#') { + altfmt = TRUE; + fmt++; + } + else if (*fmt == '-') { + ladjust = TRUE; + fmt++; + } + else if (*fmt == '+') { + plus_sign = '+'; + fmt++; + } + else if (*fmt == ' ') { + if (plus_sign == 0) + plus_sign = ' '; + fmt++; + } + else + break; + } + + if (*fmt == '0') { + padc = '0'; + fmt++; + } + + if (isdigit(*fmt)) { + while(isdigit(*fmt)) + length = 10 * length + Ctod(*fmt++); + } + else if (*fmt == '*') { + length = va_arg(args, int); + fmt++; + if (length < 0) { + ladjust = !ladjust; + length = -length; + } + } + + if (*fmt == '.') { + fmt++; + if (isdigit(*fmt)) { + prec = 0; + while(isdigit(*fmt)) + prec = 10 * prec + Ctod(*fmt++); + } + else if (*fmt == '*') { + prec = va_arg(args, int); + fmt++; + } + } + + while (*fmt == 'l'){ + longopt++; + fmt++; + } + + truncate = FALSE; + upcase = FALSE; + + switch(*fmt) { + case 'b': + case 'B': + { + register char *p; + boolean_t any; + register int i; + + u = va_arg(args, unsigned long); + p = va_arg(args, char *); + base = *p++; + printnum(u, base, putc, putc_arg); + + if (u == 0) + break; + + any = FALSE; + while ((i = *p++) != 0) { + /* NOTE: The '32' here is because ascii space */ + if (*p <= 32) { + /* + * Bit field + */ + register int j; + if (any) + (*putc)(putc_arg, ','); + else { + (*putc)(putc_arg, '<'); + any = TRUE; + } + j = *p++; + for (; (c = *p) > 32; p++) + (*putc)(putc_arg, c); + printnum((unsigned)( (u>>(j-1)) & ((2<<(i-j))-1)), + base, putc, putc_arg); + } + else if (u & (1<<(i-1))) { + if (any) + (*putc)(putc_arg, ','); + else { + (*putc)(putc_arg, '<'); + any = TRUE; + } + for (; (c = *p) > 32; p++) + (*putc)(putc_arg, c); + } + else { + for (; *p > 32; p++) + continue; + } + } + if (any) + (*putc)(putc_arg, '>'); + break; + } + + case 'c': + c = va_arg(args, int); + (*putc)(putc_arg, c); + break; + + case 't': + { + typedef struct { + unsigned version_low:10; + unsigned lthread:7; + unsigned task:11; + unsigned version_high:4; + unsigned site:17; + unsigned chief:11; + unsigned nest:4; + } tid_t; + typedef struct { + unsigned high; + unsigned low; + } lh_t; + union tid_t { + tid_t id; + lh_t lh; + } tid; + + tid = va_arg(args, union tid_t); + + if(longopt){ + + if(altfmt){ + n = 19; + } else { + n = 17; + } + + if (length > 0 && !ladjust) { + while(n < length){ + putc(putc_arg, ' '); + n++; + } + } + if(altfmt) putc(putc_arg, '['); + printnum_16( tid.lh.high, putc, putc_arg); + + putc(putc_arg, ':'); + + printnum_16( tid.lh.low, putc, putc_arg); + + if(altfmt) putc(putc_arg, ']'); + + if(length > 0 && ladjust) { + while(n < length){ + putc(putc_arg, ' '); + n++; + } + } + + } else { + + if(altfmt){ + n = 4; + } else { + n = 2; + } + + m = 1; + + m += tid.id.lthread >= 0x10; + n += tid.id.task >= 0x10; + n += tid.id.task >= 0x100; + + if (length > 0 && !ladjust && padc == ' ') { + while (n + 2 < length) { + (*putc)(putc_arg, ' '); + n++; + } + } + + if(altfmt) (*putc)(putc_arg, '['); + + if( length > 0 && !ladjust && padc == '0') { + while (n + 2 < length) { + putc(putc_arg, '0'); + n++; + } + } + + printnum(tid.id.task, 16, putc, putc_arg); + putc(putc_arg, '.'); + + if(length > 0 && !ladjust) { + while (n+m < length){ + putc(putc_arg, padc); + n++; + } + } + printnum(tid.id.lthread, 16, putc, putc_arg); + + if(altfmt) putc(putc_arg, ']'); + + if (n + m < length && ladjust) { + while (n + m < length) { + (*putc)(putc_arg, ' '); + n++; + } + } + } + + break; + } + + case 's': + { + register char *p; + register char *p2; + + if (prec == -1) + prec = 0x7fffffff; /* MAXINT */ + + p = va_arg(args, char *); + + if (p == (char *)0) + p = ""; + + if (length > 0 && !ladjust) { + n = 0; + p2 = p; + + for (; *p != '\0' && n < prec; p++) + n++; + + p = p2; + + while (n < length) { + (*putc)(putc_arg, ' '); + n++; + } + } + + n = 0; + + while (*p != '\0') { + if (++n > prec) + break; + + (*putc)(putc_arg, *p++); + } + + if (n < length && ladjust) { + while (n < length) { + (*putc)(putc_arg, ' '); + n++; + } + } + + break; + } + + + case 'o': + truncate = _doprnt_truncates; + case 'O': + base = 8; + goto print_unsigned; + + case 'd': + truncate = _doprnt_truncates; + case 'D': + base = 10; + goto print_signed; + + case 'u': + truncate = _doprnt_truncates; + case 'U': + base = 10; + goto print_unsigned; + + case 'p': + padc = '0'; + length = 8; + /* + * We do this instead of just setting altfmt to TRUE + * because we want 0 to have a 0x in front, and we want + * eight digits after the 0x -- not just 6. + */ + (*putc)(putc_arg, '0'); + (*putc)(putc_arg, 'x'); + case 'x': + truncate = _doprnt_truncates; + base = 16; + goto print_unsigned; + case 'X': + base = 16; + upcase = TRUE; + goto print_unsigned; + + case 'z': + truncate = _doprnt_truncates; + base = 16; + goto print_signed; + case 'Z': + base = 16; + upcase = TRUE; + goto print_signed; + + case 'r': + truncate = _doprnt_truncates; + case 'R': + base = radix; + goto print_signed; + + case 'n': + truncate = _doprnt_truncates; + case 'N': + base = radix; + goto print_unsigned; + + print_signed: + if (longopt>1) + n = va_arg(args, long long); + else + n = va_arg(args, long); + if (n >= 0) { + u = n; + sign_char = plus_sign; + } + else { + u = -n; + sign_char = '-'; + } + goto print_num; + + print_unsigned: + if (longopt>1) + u = va_arg(args, unsigned long long); + else + u = va_arg(args, unsigned long); + goto print_num; + + print_num: + { + char buf[MAXBUF]; /* build number here */ + register char * p = &buf[MAXBUF-1]; + static char ldigits[] = "0123456789abcdef"; + static char udigits[] = "0123456789ABCDEF"; + char *digits = ldigits; + char *prefix = 0; + + if (truncate) u = (long)((int)(u)); + if (upcase) digits = udigits; + + if (u != 0 && altfmt) { + if (base == 8) + prefix = "0"; + else if (base == 16) + prefix = "0x"; + } + + do { + *p-- = digits[u % base]; + u /= base; + } while (u != 0); + + length -= (&buf[MAXBUF-1] - p); + if (sign_char) + length--; + if (prefix) + length -= strlen(prefix); + + if (padc == ' ' && !ladjust) { + /* blank padding goes before prefix */ + while (--length >= 0) + (*putc)(putc_arg, ' '); + } + if (sign_char) + (*putc)(putc_arg, sign_char); + if (prefix) + while (*prefix) + (*putc)(putc_arg, *prefix++); + if (padc == '0') { + /* zero padding goes after sign and prefix */ + while (--length >= 0) + (*putc)(putc_arg, '0'); + } + while (++p != &buf[MAXBUF]) + (*putc)(putc_arg, *p); + + if (ladjust) { + while (--length >= 0) + (*putc)(putc_arg, ' '); + } + break; + } + + case '\0': + fmt--; + break; + + default: + (*putc)(putc_arg, *fmt); + } + fmt++; + } +} diff --git a/410user/libstdio/doprnt.h b/410user/libstdio/doprnt.h new file mode 100644 index 0000000..d2bc0f5 --- /dev/null +++ b/410user/libstdio/doprnt.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 1996 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#ifndef __DOPRNT_H_INCLUDED__ +#define __DOPRNT_H_INCLUDED__ + +#include <stdarg.h> + +void _doprnt( + register const char *fmt, + va_list args, + int radix, /* default radix - for '%r' */ + void (*putc)(), /* character output */ + char *putc_arg); /* argument for putc */ + +#endif /* __DOPRNT_H_INCLUDED__ */ diff --git a/410user/libstdio/doscan.c b/410user/libstdio/doscan.c new file mode 100644 index 0000000..f4c0a30 --- /dev/null +++ b/410user/libstdio/doscan.c @@ -0,0 +1,181 @@ +/* + * Mach Operating System + * Copyright (c) 1993 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: sscanf.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 3/93 + * + * Parse trivially simple strings + */ + +#include <stddef.h> +#include <stdarg.h> +#include <types.h> +#include <ctype.h> +#include "doscan.h" + +/* + * All I need is a miracle ... + * to keep this from growing like all the other sscanf! + */ +int +_doscan(const char *fmt, va_list vp, + int (*getc)(void *getc_arg), + void (*ungetc)(int c, void *getc_arg), + void *getc_arg) +{ + register int c; + boolean_t neg; + boolean_t discard; + boolean_t invalid; + int vals = 0; + + while ((c = *fmt++) != 0) { + + if (c != '%') { + if (isspace(c)) + { + while (isspace(c = getc(getc_arg))); + if (c == 0) break; + ungetc(c, getc_arg); + continue; + } + else if (c == getc(getc_arg)) + continue; + else + break; /* mismatch */ + } + + discard = 0; + invalid = 1; + + more_fmt: + + c = getc(getc_arg); + if (c == 0) + break; /* end of input */ + + switch (*fmt++) { + + case 'd': + { + long n = 0; + + neg = c == '-'; + if (neg) c = getc(getc_arg); + + while (c >= '0' && c <= '9') { + n = n * 10 + (c - '0'); + c = getc(getc_arg); + invalid = 0; + } + ungetc(c, getc_arg); + + if (neg) n = -n; + + /* done, store it away */ + if (!discard) + { + int *p = va_arg(vp, int *); + *p = n; + } + + break; + } + + case 'x': + { + long n = 0; + + neg = c == '-'; + if (neg) c = getc(getc_arg); + + while (1) + { + if ((c >= '0') && (c <= '9')) + n = n * 16 + (c - '0'); + else if ((c >= 'a') && (c <= 'f')) + n = n * 16 + (c - 'a' + 10); + else if ((c >= 'A') && (c <= 'F')) + n = n * 16 + (c - 'A' + 10); + else + break; + c = getc(getc_arg); + invalid = 0; + } + ungetc(c, getc_arg); /* retract lookahead */ + + if (neg) n = -n; + + /* done, store it away */ + if (!discard) + { + int *p = va_arg(vp, int *); + *p = n; + } + + break; + } + + case 's': + { + char *buf = NULL; + + if (!discard) + buf = va_arg(vp, char *); + + while (c && !isspace(c)) + { + if (!discard) + *buf++ = c; + c = getc(getc_arg); + invalid = 0; + } + ungetc(c, getc_arg); /* retract lookahead */ + + if (!discard) + *buf = 0; + + break; + } + + case '*': + discard = 1; + goto more_fmt; + + default: + break; + } + + if (invalid) + break; + else if (!discard) + vals++; + } + + return vals; +} + diff --git a/410user/libstdio/doscan.h b/410user/libstdio/doscan.h new file mode 100644 index 0000000..4973186 --- /dev/null +++ b/410user/libstdio/doscan.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 1996 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#ifndef __DOSCAN_H_INCLUDED__ +#define __DOSCAN_H_INCLUDED__ + +int _doscan(const char *fmt, va_list vp, + int (*getc)(void *getc_arg), + void (*ungetc)(int c, void *getc_arg), + void *getc_arg); + +#endif /* __DOSCAN_H_INCLUDED__ */ diff --git a/410user/libstdio/hexdump.c b/410user/libstdio/hexdump.c new file mode 100644 index 0000000..636f21c --- /dev/null +++ b/410user/libstdio/hexdump.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 1996 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include <ctype.h> +#include <stdio.h> + +/* + * Print a buffer hexdump style. Example: + * + * .---------------------------------------------------------------------------. + * | 00000000 2e2f612e 6f757400 5445524d 3d787465 ./a.out.TERM=xte | + * | 00000010 726d0048 4f4d453d 2f616673 2f63732e rm.HOME=/afs/cs. | + * | 00000020 75746168 2e656475 2f686f6d 652f6c6f utah.edu/home/lo | + * | 00000030 6d657700 5348454c 4c3d2f62 696e2f74 mew.SHELL=/bin/t | + * | 00000040 63736800 4c4f474e 414d453d 6c6f6d65 csh.LOGNAME=lome | + * | 00000050 77005553 45523d6c 6f6d6577 00504154 w.USER=lomew.PAT | + * | 00000060 483d2f61 66732f63 732e7574 61682e65 H=/afs/cs.utah.e | + * | 00000070 64752f68 6f6d652f 6c6f6d65 772f6269 du/home/lomew/bi | + * | 00000080 6e2f4073 79733a2f 6166732f 63732e75 n/@sys:/afs/cs.u | + * | 00000090 7461682e 6564 tah.ed | + * `---------------------------------------------------------------------------' + * + * It might be useful to have an option for printing out little-endianly. + * Adapted from Godmar's hook.c. + */ +void +hexdump(void *buf, int len) +{ + int i, j; + char *b = (char *)buf; + + printf(".---------------------------------------------------------------------------.\n"); + for (i = 0; i < len; i += 16) { + printf("| %08x ", i); + for (j = i; j < i+16; j++) { + if (j % 4 == 0) + printf(" "); + if (j >= len) + printf(" "); + else + printf("%02x", (unsigned char)b[j]); + } + + printf(" "); + for (j = i; j < i+16; j++) + if (j >= len) + printf(" "); + else + printf("%c", isgraph(b[j]) ? b[j] : '.'); + printf(" |\n"); + } + printf("`---------------------------------------------------------------------------'\n"); +} diff --git a/410user/libstdio/printf.c b/410user/libstdio/printf.c new file mode 100644 index 0000000..0a4a4db --- /dev/null +++ b/410user/libstdio/printf.c @@ -0,0 +1,97 @@ +/* + * Mach Operating System + * Copyright (c) 1993-1989 Carnegie Mellon University. + * Copyright (c) 1994 The University of Utah and + * the Computer Systems Laboratory (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF + * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY + * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF + * THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#include <stdio.h> +#include <stdarg.h> +#include <syscall.h> +#include "doprnt.h" + +/* This version of printf is implemented in terms of putchar and puts. */ + +#define PRINTF_BUFMAX 128 + +struct printf_state { + char buf[PRINTF_BUFMAX]; + unsigned int index; +}; + +static void +flush(struct printf_state *state) +{ + print(state->index, state->buf); + state->index = 0; +} + +static void +printf_char(char *arg, int c) +{ + struct printf_state *state = (struct printf_state *) arg; + + if (state->index >= PRINTF_BUFMAX) { + flush(state); + } + + state->buf[state->index] = c; + state->index++; + if (c == '\n') { + flush(state); + } +} + +/* + * Printing (to console) + */ +int vprintf(const char *fmt, va_list args) +{ + struct printf_state state; + + state.index = 0; + _doprnt(fmt, args, 0, (void (*)())printf_char, (char *) &state); + + if (state.index != 0) + flush(&state); + + /* _doprnt currently doesn't pass back error codes, + so just assume nothing bad happened. */ + return 0; +} + +int +printf(const char *fmt, ...) +{ + va_list args; + int err; + + va_start(args, fmt); + err = vprintf(fmt, args); + va_end(args); + + return err; +} + diff --git a/410user/libstdio/putchar.c b/410user/libstdio/putchar.c new file mode 100644 index 0000000..4dd8421 --- /dev/null +++ b/410user/libstdio/putchar.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +/* 15-410 mods by de0u 2008-09-02 ... */ +#include <stdio.h> +#include <syscall.h> + +int putchar(int c) +{ + print( 1, (char *)&c ); + return c; +} + diff --git a/410user/libstdio/puts.c b/410user/libstdio/puts.c new file mode 100644 index 0000000..d27a070 --- /dev/null +++ b/410user/libstdio/puts.c @@ -0,0 +1,14 @@ +/** @file 410user/libstdio/puts.c + * @author elly1 S2010 + * @brief The puts() libc function + */ + +#include <stdio.h> +#include <string.h> +#include <syscall.h> + +int puts(const char *s) { + print(strlen(s), (char *)s); + putchar('\n'); + return 0; +} diff --git a/410user/libstdio/sprintf.c b/410user/libstdio/sprintf.c new file mode 100644 index 0000000..c667837 --- /dev/null +++ b/410user/libstdio/sprintf.c @@ -0,0 +1,104 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#include <stdarg.h> +#include "doprnt.h" + +#define SPRINTF_UNLIMITED -1 +struct sprintf_state { + char *buf; + unsigned int len; + unsigned int max; +}; + +static void +savechar(char *arg, int c) +{ + struct sprintf_state *state = (struct sprintf_state *)arg; + + if (state->max != (unsigned int)SPRINTF_UNLIMITED) + { + if (state->len >= state->max) { + state->len++; + return; + } + } + + state->len++; + *state->buf = c; + state->buf++; +} + +int vsprintf(char *s, const char *fmt, va_list args) +{ + struct sprintf_state state; + state.max = SPRINTF_UNLIMITED; + state.len = 0; + state.buf = s; + + _doprnt(fmt, args, 0, (void (*)()) savechar, (char *) &state); + *(state.buf) = '\0'; + + return state.len; +} + +int vsnprintf(char *s, int size, const char *fmt, va_list args) +{ + struct sprintf_state state; + state.max = size - 1; + state.len = 0; + state.buf = s; + + _doprnt(fmt, args, 0, (void (*)()) savechar, (char *) &state); + *(state.buf) = '\0'; + + return state.len; +} + +int sprintf(char *s, const char *fmt, ...) +{ + va_list args; + int err; + + va_start(args, fmt); + err = vsprintf(s, fmt, args); + va_end(args); + + return err; +} + +int snprintf(char *s, int size, const char *fmt, ...) +{ + va_list args; + int err; + + va_start(args, fmt); + err = vsnprintf(s, size, fmt, args); + va_end(args); + + return err; +} + diff --git a/410user/libstdio/sscanf.c b/410user/libstdio/sscanf.c new file mode 100644 index 0000000..7f48ea9 --- /dev/null +++ b/410user/libstdio/sscanf.c @@ -0,0 +1,65 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#include <stdarg.h> +#include "doscan.h" + +static int +readchar(arg) + void *arg; +{ + return *(*(unsigned char**)arg)++; +} + +static void +unchar(c, arg) + int c; + void *arg; +{ + (void)c; + (*(unsigned char**)arg)--; +} + +int vsscanf(s, fmt, args) + char *s; + char *fmt; + va_list args; +{ + return _doscan(fmt, args, readchar, unchar, &s); +} + +int sscanf(char *s, char *fmt, ...) +{ + va_list args; + int vals; + + va_start(args, fmt); + vals = vsscanf(s, fmt, args); + va_end(args); + + return vals; +} + diff --git a/410user/libstdio/stdio.h b/410user/libstdio/stdio.h new file mode 100644 index 0000000..b25b899 --- /dev/null +++ b/410user/libstdio/stdio.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 1996-1994 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ +#ifndef _FLUX_MC_STDIO_H +#define _FLUX_MC_STDIO_H + +#ifndef ASSEMBLER +#include <stddef.h> /* For size_t, NULL */ +#include <stdarg.h> +#include <types.h> + +int putchar(int __c); +int puts(const char *__str); +int printf(const char *__format, ...) + __attribute__((__format__ (__printf__, 1, 2))); +int vprintf(const char *__format, va_list __vl); +int sprintf(char *__dest, const char *__format, ...) + __attribute__((__format__ (__printf__, 2, 3))); +int snprintf(char *__dest, size_t __size, const char *__format, ...) + __attribute__((__format__ (__printf__, 3, 4))); +int vsprintf(char *__dest, const char *__format, va_list __vl); +int vsnprintf(char *__dest, size_t __size, const char *__format, va_list __vl); +int sscanf(const char *__str, const char *__format, ...) + __attribute__((__format__ (__scanf__, 2, 3))); +void hexdump(void *buf, int len); + +#endif /* !ASSEMBLER */ + +#endif /* _FLUX_MC_STDIO_H */ diff --git a/410user/libstdio/user.mk b/410user/libstdio/user.mk new file mode 100644 index 0000000..f9bdcf0 --- /dev/null +++ b/410user/libstdio/user.mk @@ -0,0 +1,16 @@ +410ULIB_STDIO_OBJS := \ + doprnt.o \ + doscan.o \ + hexdump.o \ + printf.o \ + putchar.o \ + puts.o \ + sprintf.o \ + sscanf.o \ + +410ULIB_STDIO_OBJS := $(410ULIB_STDIO_OBJS:%=$(410UDIR)/libstdio/%) + +ALL_410UOBJS += $(410ULIB_STDIO_OBJS) +410UCLEANS += $(410UDIR)/libstdio.a + +$(410UDIR)/libstdio.a: $(410ULIB_STDIO_OBJS) diff --git a/410user/libstdlib/abs.c b/410user/libstdlib/abs.c new file mode 100644 index 0000000..3892eec --- /dev/null +++ b/410user/libstdlib/abs.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 1994 The University of Utah and + * the Computer Systems Laboratory (CSL). All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include <stdlib.h> + +#undef abs + +int abs(int val) +{ + return val >= 0 ? val : -val; +} + diff --git a/410user/libstdlib/atol.c b/410user/libstdlib/atol.c new file mode 100644 index 0000000..30f976d --- /dev/null +++ b/410user/libstdlib/atol.c @@ -0,0 +1,9 @@ +#include <stddef.h> +#include <stdlib.h> + +long +atol(const char *str) +{ + return strtol(str, NULL, 10); +} + diff --git a/410user/libstdlib/ctype.c b/410user/libstdlib/ctype.c new file mode 100644 index 0000000..2159f5a --- /dev/null +++ b/410user/libstdlib/ctype.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 1996-1994 The University of Utah and + * the Computer Systems Laboratory (CSL). All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +int isascii(int c) +{ + return ((c) >= 0) && ((c) <= 126); +} + +int iscntrl(int c) +{ + return ((c) < ' ') || ((c) > 126); +} + +int isdigit(int c) +{ + return ((c) >= '0') && ((c) <= '9'); +} + +int isgraph(int c) +{ + return ((c) > ' ') && ((c) <= 126); +} + +int islower(int c) +{ + return (c >= 'a') && (c <= 'z'); +} + +int isprint(int c) +{ + return ((c) >= ' ') && ((c) <= 126); +} + +int isspace(int c) +{ + return ((c) == ' ') || ((c) == '\f') + || ((c) == '\n') || ((c) == '\r') + || ((c) == '\t') || ((c) == '\v'); +} + +int isupper(int c) +{ + return (c >= 'A') && (c <= 'Z'); +} + +int isxdigit(int c) +{ + return isdigit(c) || + ((c >= 'A') && (c <= 'F')) || + ((c >= 'a') && (c <= 'f')); +} + +int isalpha(int c) +{ + return islower(c) || isupper(c); +} + +int isalnum(int c) +{ + return isalpha(c) || isdigit(c); +} + +int ispunct(int c) +{ + return isgraph(c) && !isalnum(c); +} + +int toupper(int c) +{ + return ((c >= 'a') && (c <= 'z')) ? (c - 'a' + 'A') : c; +} + +int tolower(int c) +{ + return ((c >= 'A') && (c <= 'Z')) ? (c - 'A' + 'a') : c; +} diff --git a/410user/libstdlib/ctype.h b/410user/libstdlib/ctype.h new file mode 100644 index 0000000..72eaa20 --- /dev/null +++ b/410user/libstdlib/ctype.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 1996-1994 The University of Utah and + * the Computer Systems Laboratory (CSL). All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ +#ifndef _FLUX_MC_CTYPE_H_ +#define _FLUX_MC_CTYPE_H_ + +int isascii(int c); +int iscntrl(int c); +int isdigit(int c); +int isgraph(int c); +int islower(int c); +int isprint(int c); +int isspace(int c); +int isupper(int c); +int isxdigit(int c); +int isalpha(int c); +int isalnum(int c); +int ispunct(int c); +int toupper(int c); +int tolower(int c); + + +#endif /* _FLUX_MC_CTYPE_H_ */ diff --git a/410user/libstdlib/exit.c b/410user/libstdlib/exit.c new file mode 100644 index 0000000..4fab152 --- /dev/null +++ b/410user/libstdlib/exit.c @@ -0,0 +1,15 @@ +/* + * exit.c + * For new set_status()/vanish() interface, Spring 2007 + * @author Dave Eckhardt (de0u) + */ + +#include <syscall.h> + +void set_status(int status); +void vanish(void) NORETURN; + +void exit(int status) +{ + task_vanish(status); +} diff --git a/410user/libstdlib/qsort.c b/410user/libstdlib/qsort.c new file mode 100644 index 0000000..3c00eb6 --- /dev/null +++ b/410user/libstdlib/qsort.c @@ -0,0 +1,170 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <types.h> +#include <stdlib.h> + +static inline char *med3(char *, char *, char *, int (*)()); +static inline void swapfunc(char *, char *, int, int); + +#define min(a, b) ((a) < (b) ? (a) : (b)) + +/* + * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". + */ +#define swapcode(TYPE, parmi, parmj, n) { \ + long i = (n) / sizeof (TYPE); \ + register TYPE *pi = (TYPE *) (parmi); \ + register TYPE *pj = (TYPE *) (parmj); \ + do { \ + register TYPE t = *pi; \ + *pi++ = *pj; \ + *pj++ = t; \ + } while (--i > 0); \ +} + +#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ + es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; + +static inline void +swapfunc(a, b, n, swaptype) + char *a, *b; + int n, swaptype; +{ + if(swaptype <= 1) + swapcode(long, a, b, n) + else + swapcode(char, a, b, n) +} + +#define swap(a, b) \ + if (swaptype == 0) { \ + long t = *(long *)(a); \ + *(long *)(a) = *(long *)(b); \ + *(long *)(b) = t; \ + } else \ + swapfunc(a, b, es, swaptype) + +#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) + +static inline char * +med3(a, b, c, cmp) + char *a, *b, *c; + int (*cmp)(); +{ + return cmp(a, b) < 0 ? + (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a )) + :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c )); +} + +void +qsort(a, n, es, cmp) + void *a; + size_t n, es; + int (*cmp)(); +{ + char *pa, *pb, *pc, *pd, *pl, *pm, *pn; + int d, r, swaptype, swap_cnt; + +loop: SWAPINIT(a, es); + swap_cnt = 0; + if (n < 7) { + for (pm = a + es; pm < (char *) a + n * es; pm += es) + for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + pm = a + (n / 2) * es; + if (n > 7) { + pl = a; + pn = a + (n - 1) * es; + if (n > 40) { + d = (n / 8) * es; + pl = med3(pl, pl + d, pl + 2 * d, cmp); + pm = med3(pm - d, pm, pm + d, cmp); + pn = med3(pn - 2 * d, pn - d, pn, cmp); + } + pm = med3(pl, pm, pn, cmp); + } + swap(a, pm); + pa = pb = a + es; + + pc = pd = a + (n - 1) * es; + for (;;) { + while (pb <= pc && (r = cmp(pb, a)) <= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pa, pb); + pa += es; + } + pb += es; + } + while (pb <= pc && (r = cmp(pc, a)) >= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pc, pd); + pd -= es; + } + pc -= es; + } + if (pb > pc) + break; + swap(pb, pc); + swap_cnt = 1; + pb += es; + pc -= es; + } + if (swap_cnt == 0) { /* Switch to insertion sort */ + for (pm = a + es; pm < (char *) a + n * es; pm += es) + for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + + pn = a + n * es; + r = min(pa - (char *)a, pb - pa); + vecswap(a, pb - r, r); + r = min(pd - pc, pn - pd - (int)es); + vecswap(pb, pn - r, r); + if ((r = pb - pa) > (int)es) + qsort(a, r / es, es, cmp); + if ((r = pd - pc) > (int)es) { + /* Iterate rather than recurse to save stack space */ + a = pn - r; + n = r / es; + goto loop; + } +/* qsort(pn - r, r / es, es, cmp);*/ +} diff --git a/410user/libstdlib/rand.c b/410user/libstdlib/rand.c new file mode 100644 index 0000000..fcff0b5 --- /dev/null +++ b/410user/libstdlib/rand.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1994 The University of Utah and + * the Computer Systems Laboratory (CSL). All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include <stdlib.h> + +static unsigned seed[2]; + +int +rand(void) +{ + seed[0] += 0xa859c317; + seed[0] += (seed[1] << 13) | (seed[1] >> 19); + seed[1] += seed[0]; + return seed[0] & 0x7FFFFFFF; +} + +void +srand(unsigned new_seed) +{ + seed[0] = seed[1] = new_seed; +} + +#if 0 /* test code */ + +#define CYCLES 100000000 + +void main(int argc, char **argv) +{ + unsigned orig_seed = atol(argv[1]); + int i; + + srand(orig_seed); + for(i = 0; i < CYCLES; i++) + { + int r = rand(); + /*printf("%08x\n", r);*/ + if ((seed[0] == orig_seed) && (seed[1] == orig_seed)) + { + printf("repeates after %d cycles\n", i); + exit(0); + } + } + printf("still not repeating after %d cycles\n", CYCLES); +} + +#endif + diff --git a/410user/libstdlib/stdlib.h b/410user/libstdlib/stdlib.h new file mode 100644 index 0000000..a30aa65 --- /dev/null +++ b/410user/libstdlib/stdlib.h @@ -0,0 +1,30 @@ +#ifndef _STDLIB_H_ +#define _STDLIB_H_ + +#include <stddef.h> /* For size_t, NULL */ +#include <malloc.h> /* "Listen to what the man says" */ + +/* start user-land only */ + +/* Apologies for the gcc-ism, but gcc gets angry w/o it */ +void exit(int status) __attribute__((__noreturn__)); + +/* end user-land only */ + +long atol(const char *__str); +#define atoi(str) ((int)atol(str)) + +long strtol(const char *__p, char **__out_p, int __base); +unsigned long strtoul(const char *__p, char **__out_p, int __base); + +#define RAND_MAX ((signed int)0x7fffffff) +int rand(void); +void srand(unsigned new_seed); + +int abs(int val); + +void qsort(void *a, size_t n, size_t es, int (*cmp)(char*, char*)); + +void panic(const char *, ...); + +#endif diff --git a/410user/libstdlib/strtol.c b/410user/libstdlib/strtol.c new file mode 100644 index 0000000..90c4ef4 --- /dev/null +++ b/410user/libstdlib/strtol.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 1995-1994 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include <stdlib.h> +#include <ctype.h> +#include <string.h> + +long strtol(const char *p, char **out_p, int base) +{ + long v = 0; + int is_neg = 0; + + while (isspace(*p)) + p++; + if (*p == '-') + is_neg = 1, p++; + else if (*p == '+') + is_neg = 0; + if (((base == 16) || (base == 0)) && + ((*p == '0') && ((p[1] == 'x') || (p[1] == 'X')))) + { + p += 2; + base = 16; + } + if (base == 0) + { + if (*p == '0') + base = 8; + else + base = 10; + } + while (1) + { + char c = *p; + if ((c >= '0') && (c <= '9') && (c - '0' < base)) + v = (v * base) + (c - '0'); + else if ((c >= 'a') && (c <= 'z') && (c - 'a' + 10 < base)) + v = (v * base) + (c - 'a' + 10); + else if ((c >= 'A') && (c <= 'Z') && (c - 'A' + 10 < base)) + v = (v * base) + (c - 'A' + 10); + else + break; + p++; + } + if (is_neg) + v = -v; + if (out_p) *out_p = (char*)p; + return v; +} + diff --git a/410user/libstdlib/strtoul.c b/410user/libstdlib/strtoul.c new file mode 100644 index 0000000..59d8f2a --- /dev/null +++ b/410user/libstdlib/strtoul.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1995-1994 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include <stdlib.h> +#include <ctype.h> +#include <string.h> + +unsigned long strtoul(const char *p, char **out_p, int base) +{ + unsigned long v = 0; + + while (isspace(*p)) + p++; + if (((base == 16) || (base == 0)) && + ((*p == '0') && ((p[1] == 'x') || (p[1] == 'X')))) + { + p += 2; + base = 16; + } + if (base == 0) + { + if (*p == '0') + base = 8; + else + base = 10; + } + while (1) + { + char c = *p; + if ((c >= '0') && (c <= '9') && (c - '0' < base)) + v = (v * base) + (c - '0'); + else if ((c >= 'a') && (c <= 'z') && (c - 'a' + 10 < base)) + v = (v * base) + (c - 'a' + 10); + else if ((c >= 'A') && (c <= 'Z') && (c - 'A' + 10 < base)) + v = (v * base) + (c - 'A' + 10); + else + break; + p++; + } + + if (out_p) *out_p = (char*)p; + return v; +} + diff --git a/410user/libstdlib/user.mk b/410user/libstdlib/user.mk new file mode 100644 index 0000000..e1ed87f --- /dev/null +++ b/410user/libstdlib/user.mk @@ -0,0 +1,17 @@ +410ULIB_STDLIB_OBJS := \ + abs.o \ + atol.o \ + ctype.o \ + exit.o \ + qsort.o \ + rand.o \ + strtol.o \ + strtoul.o \ + + +410ULIB_STDLIB_OBJS := $(410ULIB_STDLIB_OBJS:%=$(410UDIR)/libstdlib/%) + +ALL_410UOBJS += $(410ULIB_STDLIB_OBJS) +410UCLEANS += $(410UDIR)/libstdlib.a + +$(410UDIR)/libstdlib.a: $(410ULIB_STDLIB_OBJS) diff --git a/410user/libstring/memcmp.c b/410user/libstring/memcmp.c new file mode 100644 index 0000000..204fd4b --- /dev/null +++ b/410user/libstring/memcmp.c @@ -0,0 +1,53 @@ +/* + * Mach Operating System + * Copyright (c) 1992,1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: limach/memcmp.c + * Author: Robert V. Baron at Carnegie Mellon + * Date: Oct 13, 1992 + * Abstract: + * strcmp (s1, s2) compares the strings "s1" and "s2". + * It returns 0 if the strings are identical. It returns + * > 0 if the first character that differs into two strings + * is larger in s1 than in s2 or if s1 is longer than s2 and + * the contents are identical up to the length of s2. + * It returns < 0 if the first differing character is smaller + * in s1 than in s2 or if s1 is shorter than s2 and the + * contents are identical upto the length of s1. + */ + +int +memcmp(const void *s1v, const void *s2v, int size) +{ + register const char *s1 = s1v, *s2 = s2v; + register unsigned int a, b; + + while (size-- > 0) { + if ((a = *s1++) != (b = *s2++)) + return (a-b); + } + + return 0; +} diff --git a/410user/libstring/memset.c b/410user/libstring/memset.c new file mode 100644 index 0000000..6a40159 --- /dev/null +++ b/410user/libstring/memset.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include <types.h> + +void * +memset(void *tov, int c, size_t len) +{ + register char *to = tov; + + while (len-- > 0) + *to++ = c; + + return tov; +} + diff --git a/410user/libstring/rindex.c b/410user/libstring/rindex.c new file mode 100644 index 0000000..847b3dc --- /dev/null +++ b/410user/libstring/rindex.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 1994 The University of Utah and + * the Computer Systems Laboratory (CSL). All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include <string.h> +#include <stdlib.h> + +char *rindex(const char *s, int c) +{ + char *it = 0; + + while (1) + { + if (*s == c) + it = (char *)s; + if (*s == 0) + return it; + s++; + } +} + diff --git a/410user/libstring/strcat.c b/410user/libstring/strcat.c new file mode 100644 index 0000000..b0906a0 --- /dev/null +++ b/410user/libstring/strcat.c @@ -0,0 +1,38 @@ +/* + * Mach Operating System + * Copyright (c) 1992,1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +char * +strcat(s, add) +register char *s, *add; +{ +register char *ret = s; + + while (*s) s++; + + while ((*s++ = *add++) != 0); + + return ret; +} diff --git a/410user/libstring/strchr.c b/410user/libstring/strchr.c new file mode 100644 index 0000000..5eff9e5 --- /dev/null +++ b/410user/libstring/strchr.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include <string.h> + +char *strchr(const char *s, int c) +{ + while (1) + { + if (*s == c) + return (char*)s; + if (*s == 0) + return 0; + s++; + } +} + diff --git a/410user/libstring/strcmp.c b/410user/libstring/strcmp.c new file mode 100644 index 0000000..77cd82d --- /dev/null +++ b/410user/libstring/strcmp.c @@ -0,0 +1,55 @@ +/* + * Mach Operating System + * Copyright (c) 1992,1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: limach/strcmp.c + * Author: Robert V. Baron at Carnegie Mellon + * Date: Oct 13, 1992 + * Abstract: + * strcmp (s1, s2) compares the strings "s1" and "s2". + * It returns 0 if the strings are identical. It returns + * > 0 if the first character that differs into two strings + * is larger in s1 than in s2 or if s1 is longer than s2 and + * the contents are identical up to the length of s2. + * It returns < 0 if the first differing character is smaller + * in s1 than in s2 or if s1 is shorter than s2 and the + * contents are identical upto the length of s1. + */ + +int +strcmp(s1,s2) +register unsigned char *s1, *s2; +{ +register unsigned int a, b; + + + + while ( (a = *s1++), (b = *s2++), a && b) { + if (a != b) + return (a-b); + } + + return a-b; +} diff --git a/410user/libstring/strcpy.c b/410user/libstring/strcpy.c new file mode 100644 index 0000000..66df3b9 --- /dev/null +++ b/410user/libstring/strcpy.c @@ -0,0 +1,45 @@ +/* + * Mach Operating System + * Copyright (c) 1992,1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: libmach_sa/strcpy.c + * Author: Robert V. Baron at Carnegie Mellon + * Date: Oct 13, 1992 + * Abstract: + * strcpy copies the contents of the string "from" including + * the null terminator to the string "to". A pointer to "to" + * is returned. + */ + +char * +strcpy(to,from) +register char *to, *from; +{ +register char *ret = to; + + while ((*to++ = *from++) != 0); + + return ret; +} diff --git a/410user/libstring/strcspn.c b/410user/libstring/strcspn.c new file mode 100644 index 0000000..97b2c91 --- /dev/null +++ b/410user/libstring/strcspn.c @@ -0,0 +1,64 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <types.h> +#include <string.h> + +/* + * Span the complement of string s2. + */ +size_t +strcspn(s1, s2) + const char *s1; + register const char *s2; +{ + register const char *p, *spanp; + register char c, sc; + + /* + * Stop as soon as we find any character from s2. Note that there + * must be a NUL in s2; it suffices to stop when we find that, too. + */ + for (p = s1;;) { + c = *p++; + spanp = s2; + do { + if ((sc = *spanp++) == c) + return (p - 1 - s1); + } while (sc != 0); + } + /* NOTREACHED */ +} diff --git a/410user/libstring/strdup.c b/410user/libstring/strdup.c new file mode 100644 index 0000000..7275355 --- /dev/null +++ b/410user/libstring/strdup.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 1994 The University of Utah and + * the Computer Systems Laboratory (CSL). All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include <string.h> +#include <stdlib.h> + + + +char *strdup(const char *src) +{ + char *buf = malloc(strlen(src)+1); + if (buf) + strcpy(buf, src); + return buf; +} + diff --git a/410user/libstring/string.h b/410user/libstring/string.h new file mode 100644 index 0000000..e47934a --- /dev/null +++ b/410user/libstring/string.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1994 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ +#ifndef _FLUX_MC_STRING_H_ +#define _FLUX_MC_STRING_H_ + +#include <types.h> + +size_t strlen(const char *__s); +char *strcpy(char *__dest, const char *__src); +char *strncpy(char *__dest, const char *__src, size_t __n); +char *strdup(const char *__s); +char *strcat(char *__dest, const char *__src); +char *strncat(char *__dest, const char *__src, size_t __n); +int strcmp(const char *__a, const char *__b); +int strncmp(const char *__a, const char *__b, size_t __n); +char *strchr(const char *__s, int __c); +char *strrchr(const char *__s, int __c); +char *strstr(const char *__haystack, const char *__needle); +char *strtok(char *__s, const char *__delim); +char *strpbrk(const char *__s1, const char *__s2); +size_t strspn(const char *__s1, const char *__s2); +size_t strcspn(const char *__s1, const char *__s2); + +void *memset(void *__to, int __ch, unsigned int __n); +int memcmp(const void *s1v, const void *s2v, int size); + +/* FIXME These are defined here only by tradition... we should move them. */ +void *memcpy(void *__to, const void *__from, unsigned int __n); +void *memmove(void *__to, const void *__from, unsigned int __n); + +/*** BSD compatibility functions; do not use in new code ***/ + +char *index(const char *__s, int __c); +char *rindex(const char *__s, int __c); + +void bcopy(const void *__from, void *__to, unsigned int __n); +void bzero(void *__to, unsigned int __n); + +#endif /* _FLUX_MC_STRING_H_ */ diff --git a/410user/libstring/strlen.c b/410user/libstring/strlen.c new file mode 100644 index 0000000..089b028 --- /dev/null +++ b/410user/libstring/strlen.c @@ -0,0 +1,45 @@ +/* + * Mach Operating System + * Copyright (c) 1992,1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: limach/strlen.c + * Author: Robert V. Baron at Carnegie Mellon + * Date: Oct 13, 1992 + * Abstract: + * strlen returns the number of characters in "string" preceeding + * the terminating null character. + */ + +int +strlen(string) + register char *string; +{ +register char *ret = string; + + while (*string++); + + return string - 1 - ret; + +} diff --git a/410user/libstring/strncat.c b/410user/libstring/strncat.c new file mode 100644 index 0000000..480b3b5 --- /dev/null +++ b/410user/libstring/strncat.c @@ -0,0 +1,64 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <types.h> +#include <string.h> + +/* + * Concatenate src on the end of dst. At most strlen(dst)+n+1 bytes + * are written at dst (at most n+1 bytes being appended). Return dst. + */ +char * +strncat(dst, src, n) + char *dst; + const char *src; + register size_t n; +{ + if (n != 0) { + register char *d = dst; + register const char *s = src; + + while (*d != 0) + d++; + do { + if ((*d = *s++) == 0) + break; + d++; + } while (--n != 0); + *d = 0; + } + return (dst); +} diff --git a/410user/libstring/strncmp.c b/410user/libstring/strncmp.c new file mode 100644 index 0000000..6ce3f30 --- /dev/null +++ b/410user/libstring/strncmp.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 1994 The University of Utah and + * the Computer Systems Laboratory (CSL). All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include <string.h> + +int +strncmp(const char *s1, const char *s2, size_t n) +{ + while (1) + { + if (n <= 0) + return 0; + if (*s1 != *s2) + return *s1 - *s2; + if (*s1 == 0) + return 0; + + s1++; + s2++; + n--; + } +} + diff --git a/410user/libstring/strncpy.c b/410user/libstring/strncpy.c new file mode 100644 index 0000000..19cf89a --- /dev/null +++ b/410user/libstring/strncpy.c @@ -0,0 +1,51 @@ +/* + * Mach Operating System + * Copyright (c) 1992,1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: libmach_sa/strncpy.c + * Author: Mary R. Thompson at Carnegie Mellon + * Date: Oct 13, 1992 + * Abstract: + * strncpy copies "count" characters from the "from" string to + * the "to" string. If "from" contains less than "count" characters + * "to" will be padded with null characters until exactly "count" + * characters have been written. The return value is a pointer + * to the "to" string. + */ + +char * +strncpy(to, from, count) + register char *to, *from; + register int count; +{ + register char *ret = to; + + while (count-- > 0 && (*to++ = *from++)); + + while (count-- > 0) + *to++ = '\0'; + + return ret; +} diff --git a/410user/libstring/strpbrk.c b/410user/libstring/strpbrk.c new file mode 100644 index 0000000..12ddef9 --- /dev/null +++ b/410user/libstring/strpbrk.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1985, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <types.h> +#include <stddef.h> +#include <string.h> + +/* + * Find the first occurrence in s1 of a character in s2 (excluding NUL). + */ +char * +strpbrk(s1, s2) + register const char *s1, *s2; +{ + register const char *scanp; + register int c, sc; + + while ((c = *s1++) != 0) { + for (scanp = s2; (sc = *scanp++) != 0;) + if (sc == c) + return ((char *)(s1 - 1)); + } + return (NULL); +} diff --git a/410user/libstring/strrchr.c b/410user/libstring/strrchr.c new file mode 100644 index 0000000..e7b5792 --- /dev/null +++ b/410user/libstring/strrchr.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 1996 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include <string.h> +#include <stddef.h> + +char * +strrchr(const char *s, int c) +{ + char *save; + + for (save = NULL; *s != '\0'; s++) + if (*s == c) + save = (char *)s; + + return save; +} diff --git a/410user/libstring/strspn.c b/410user/libstring/strspn.c new file mode 100644 index 0000000..a493f8f --- /dev/null +++ b/410user/libstring/strspn.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <types.h> +#include <string.h> + +/* + * Span the string s2 (skip characters that are in s2). + */ +size_t +strspn(s1, s2) + const char *s1; + register const char *s2; +{ + register const char *p = s1, *spanp; + register char c, sc; + + /* + * Skip any characters in s2, excluding the terminating \0. + */ +cont: + c = *p++; + for (spanp = s2; (sc = *spanp++) != 0;) + if (sc == c) + goto cont; + return (p - 1 - s1); +} diff --git a/410user/libstring/strstr.c b/410user/libstring/strstr.c new file mode 100644 index 0000000..7c2fb55 --- /dev/null +++ b/410user/libstring/strstr.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 1994 The University of Utah and + * the Computer Systems Laboratory (CSL). All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include <string.h> +#include <stdlib.h> + +char *strstr(const char *haystack, const char *needle) +{ + int hlen = strlen(haystack); + int nlen = strlen(needle); + + while (hlen >= nlen) + { + if (!memcmp(haystack, needle, nlen)) + return (void*)haystack; + + haystack++; + hlen--; + } + return 0; +} + diff --git a/410user/libstring/strtok.c b/410user/libstring/strtok.c new file mode 100644 index 0000000..ba4f85d --- /dev/null +++ b/410user/libstring/strtok.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <string.h> +#include <stddef.h> + +char * +strtok(s, delim) + register char *s; + register const char *delim; +{ + register char *spanp; + register int c, sc; + char *tok; + static char *last; + + + if (s == NULL && (s = last) == NULL) + return (NULL); + + /* + * Skip (span) leading delimiters (s += strspn(s, delim), sort of). + */ +cont: + c = *s++; + for (spanp = (char *)delim; (sc = *spanp++) != 0;) { + if (c == sc) + goto cont; + } + + if (c == 0) { /* no non-delimiter characters */ + last = NULL; + return (NULL); + } + tok = s - 1; + + /* + * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). + * Note that delim must have one NUL; we stop if we see that, too. + */ + for (;;) { + c = *s++; + spanp = (char *)delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + last = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} diff --git a/410user/libstring/user.mk b/410user/libstring/user.mk new file mode 100644 index 0000000..60f0a39 --- /dev/null +++ b/410user/libstring/user.mk @@ -0,0 +1,27 @@ +410ULIB_STRING_OBJS:= \ + memcmp.o \ + memset.o \ + rindex.o \ + strcat.o \ + strchr.o \ + strcmp.o \ + strcpy.o \ + strcspn.o \ + strdup.o \ + strlen.o \ + strncat.o \ + strncmp.o \ + strncpy.o \ + strpbrk.o \ + strrchr.o \ + strspn.o \ + strstr.o \ + strtok.o \ + + +410ULIB_STRING_OBJS:= $(410ULIB_STRING_OBJS:%=$(410UDIR)/libstring/%) + +ALL_410UOBJS += $(410ULIB_STRING_OBJS) +410UCLEANS += $(410UDIR)/libstring.a + +$(410UDIR)/libstring.a: $(410ULIB_STRING_OBJS) diff --git a/410user/libtest/report.c b/410user/libtest/report.c new file mode 100644 index 0000000..96d29a3 --- /dev/null +++ b/410user/libtest/report.c @@ -0,0 +1,98 @@ +/** @file 410user/libtest/report.c + * @brief Test reporting implementation + * @author elly1 U2009 + */ + +#include <stdio.h> /* snprintf */ +#include <stdlib.h> /* exit */ +#include <report.h> + +#include "410_tests.h" /* TEST_START_*, TEST_END_*, TEST_PFX */ + +/* This is a GNUism used for the sake of maintainability. This way nothing + * horrible will happen if someone reorders the START_* constants in the header + * file. */ +const char *start_msgs[] = { + [START_CMPLT] = TEST_START_CMPLT, + [START_ABORT] = TEST_START_ABORT, + [START_4EVER] = TEST_START_4EVER, +}; + +const char *end_msgs[] = { + [END_SUCCESS] = TEST_END_SUCCESS, + [END_FAIL] = TEST_END_FAIL, +}; + +void format_start(char *buf, int len, int type) { + snprintf(buf, len, "%s%s%s", TEST_PFX, test_name, start_msgs[type]); +} + +void format_end(char *buf, int len, int type) { + snprintf(buf, len, "%s%s%s", TEST_PFX, test_name, end_msgs[type]); +} + +void format_misc(char *buf, int len, const char *msg) { + snprintf(buf, len, "%s%s%s", TEST_PFX, test_name, msg); +} + +void format_err(char *buf, int len, const char *msg, int code) { + snprintf(buf, len, "%s%s%s%d", TEST_PFX, test_name, msg, code); +} + +void report_start(int type) { + char buf[256]; + format_start(buf, sizeof(buf), type); + sim_puts(buf); +} + +void report_end(int type) { + char buf[256]; + format_end(buf, sizeof(buf), type); + sim_puts(buf); + + int success = (type == END_SUCCESS) ? 1 : 0; + sim_update_scoreboard((char *)test_name, success); +} + +void report_misc(const char *msg) { + char buf[256]; + format_misc(buf, sizeof(buf), msg); + sim_puts(buf); +} + +void report_fmt(const char *fmt, ...) { + va_list ap; + char b[256]; + char buf[256]; + va_start(ap, fmt); + vsnprintf(b, sizeof(b), fmt, ap); + va_end(ap); + snprintf(buf, sizeof(buf), "%s%s%s", TEST_PFX, test_name, b); + sim_puts(buf); +} + +void report_err(const char *msg, int code) { + char buf[256]; + format_err(buf, sizeof(buf), msg, code); + sim_puts(buf); +} + +void report_fatal(const char *msg, int code) { + report_err(msg, code); + report_end(END_FAIL); +} + +void report_on_err(const char *exp, int line, int v) { + char buf[256]; + if (v >= 0) { return; } + snprintf(buf, sizeof(buf), "%s%sErr %d on line %d: `%s'", + TEST_PFX, test_name, v, line, exp); + sim_puts(buf); +} + +void fatal_on_err(const char *exp, int line, int v) { + report_on_err(exp, line, v); + if (v >= 0) { return; } + report_end(END_FAIL); + exit(v); +} diff --git a/410user/libtest/report.h b/410user/libtest/report.h new file mode 100644 index 0000000..496754b --- /dev/null +++ b/410user/libtest/report.h @@ -0,0 +1,109 @@ +/** @file 410user/libtest/report.h + * @brief Test reporting interface + * @author elly1 U2009 + */ + +#ifndef LIBTEST_REPORT_H +#define LIBTEST_REPORT_H + +extern const char* test_name; /* Defined by the test in question with + * DEF_TEST_NAME() */ + +enum { + START_CMPLT = 0, + START_ABORT = 1, + START_4EVER = 2, +}; + +/** @brief Formats a test start message into a buffer. + * @param buf Buffer to format into. + * @param len Length of the buffer. + * @param type Type of test start. + * @return Void. + */ +extern void format_start(char *buf, int len, int type); + +/** @brief Reports the start of a test. + * @param type Type of test start. + */ +extern void report_start(int type); + +enum { + END_SUCCESS = 0, + END_FAIL = 1, +}; + +/** @brief Formats a test end message into a buffer. + * @param buf Buffer to format into. + * @param len Length of the buffer. + * @param type Type of test ending. + * @return Void. + */ +extern void format_end(char *buf, int len, int type); + +/** @brief Reports the end of a test. + * @param type Type of test end. + */ +extern void report_end(int type); + +/** @brief Formats a miscellaneous message into a buffer. + * @param buf Buffer to format into. + * @param len Length of the buffer. + * @param msg Message to format. + * @return Void. + */ +extern void format_misc(char *buf, int len, const char *msg); + +/** @brief Report a miscellaneous happenstance. + * @param msg Happenstance. + * @return Void. + */ +extern void report_misc(const char *msg); + +/** @brief Report an arbitrary formatted message. + * @param fmt Format. + * @param ... Varargs. + * @return Void. + */ +extern void report_fmt(const char *fmt, ...); + +/** @brief Formats an error message into a buffer. + * @param buf Buffer to format into. + * @param len Length of the buffer. + * @param msg Message to format. + * @param code Error code. + * @return Void. + */ +extern void format_err(char *buf, int len, const char *msg, int code); + +/** @brief Report an error. + * @param msg Error message. + * @param code Error code. + * @return Void. + */ +extern void report_err(const char *msg, int code); + +/** @brief Report an error, and fail out. + * @param msg Error message. + * @param code Error code. + * @return Void. + */ +extern void report_fatal(const char *msg, int code); + +/** @brief Require that an expression succeed. + * @param exp Expression, as a string. + * @param line Line number of the expression. + * @param v Expression value. + * @return Void. + */ +extern void report_on_err(const char *exp, int line, int v); + +/** @brief Fail the test if an expression fails. + * @param exp Expression, as a string. + * @param line Line number of the expression. + * @param v Expression value. + * @return Void. + */ +extern void fatal_on_err(const char *exp, int line, int v); + +#endif /* !LIBTEST_REPORT_H */ diff --git a/410user/libtest/test.c b/410user/libtest/test.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/410user/libtest/test.c diff --git a/410user/libtest/test.h b/410user/libtest/test.h new file mode 100644 index 0000000..e47bfb5 --- /dev/null +++ b/410user/libtest/test.h @@ -0,0 +1,52 @@ +/** @file 410user/libtest/test.h + * @brief Test library. + * @author elly1 U2009 + */ + +#ifndef LIBTEST_TEST_H +#define LIBTEST_TEST_H + +/** @brief Jump to 'func' with the system under low-memory conditions. + * The reason why this takes a function pointer may not be immediately clear. + * Once exhaustion() returns to C, the compiler is immediately free to save off + * all the registers and generally touch the stack; this could cause a failed + * stack page allocation and lead to the thread being killed, which would fail + * the test. As such, exhaustion guarantees that once you are out of memory, it + * will not touch the stack on your behalf. + * + * @param func Function to jump to. + * @param arg Argument passed to func in %ebx. + * @return Does not return. + */ +extern void exhaustion(void (*func)(void *), void *arg) __attribute__((noreturn)); + +/** @brief Fork, and exit immediately, printing success regardless of what + * happened. Does not touch the stack at all. + * @param arg Argument passed in *in %ebx*. + * @return Does not return. + * + * NOTE: + * Do not call this function directly. It is designed to be passed into + * exhaustion(). + */ +extern void fork_and_exit(void *arg) __attribute__((noreturn)); + +/** @brief Exit immediately, with a success message. + * @param arg Argument passed in *in %ebx*. + * @return Does not return. + * + * See the note attached to fork_and_exit(). + */ +extern void exit_success(void *arg) __attribute__((noreturn)); + +/** @brief Execute an illegal instruction. + * @return Void. + */ +extern void illegal(void); + +/** @brief Assuredly invoke the misbehave() system call + * @return Void ("you are not expected to understand this") + */ +extern void assuredly_misbehave(int mode); + +#endif /* !LIBTEST_TEST_H */ diff --git a/410user/libtest/testasm.S b/410user/libtest/testasm.S new file mode 100644 index 0000000..d0179ab --- /dev/null +++ b/410user/libtest/testasm.S @@ -0,0 +1,82 @@ +/** @file 410user/libtest/testasm.S + * @brief Test library. + * @author elly1 U2009 + */ + +#include <simics.h> +#include <syscall_int.h> + +.global exhaustion + +#define EX_BASE 0x20000000 +#define EX_SIZE 1024 * 1024 * 1024 + +/* %edi - continuation + * %esi - syscall arg frame + * %ebx - argument + */ +exhaustion: + mov 4(%esp), %edi + mov 8(%esp), %ebx + lea -8(%esp), %esi /* argument frame space */ + mov $EX_BASE, %ecx + mov $EX_SIZE, %edx + mov $4, %esp /* don't tempt the user to think that their stack is + * still live */ +loop: + cmp $4096, %edx + jb 1f + mov %ecx, (%esi) + mov %edx, 4(%esi) + int $NEW_PAGES_INT + test %eax, %eax + jnz smaller + add %edx, %ecx + jmp loop +smaller: + shr $1, %edx + jmp loop +1: + jmp *%edi + +.global fork_and_exit + +fork_and_exit: + mov %ebx, %ecx + int $FORK_INT + test %eax, %eax + jz 1f + INLINE_SIMCALL(SIM_PUTS, %ecx, $0) +1: + mov $0, %esi + int $SET_STATUS_INT + int $VANISH_INT + +.global exit_success + +exit_success: + mov %ebx, %ecx + INLINE_SIMCALL(SIM_PUTS, %ecx, $0) + INLINE_SIMCALL(SIM_TEST_REPORT, %ecx, $1) + mov $0, %esi + int $SET_STATUS_INT + int $VANISH_INT + +.global illegal + +illegal: + xor %eax, %eax + mov %eax, %cr0 + ret + +/* Don't code like this: "authorized personnel only". */ +.global assuredly_misbehave +assuredly_misbehave: + pushl %ebp + movl %esp, %ebp + pusha + movl 8(%ebp), %esi + int $MISBEHAVE_INT + popa + leave + ret diff --git a/410user/libtest/user.mk b/410user/libtest/user.mk new file mode 100644 index 0000000..a302d02 --- /dev/null +++ b/410user/libtest/user.mk @@ -0,0 +1,6 @@ +410U_TEST_OBJS := test.o testasm.o report.o +410U_TEST_OBJS := $(410U_TEST_OBJS:%=$(410UDIR)/libtest/%) +ALL_410UOBJS += $(410U_TEST_OBJS) +410UCLEANS += $(410UDIR)/libtest.a + +$(410UDIR)/libtest.a: $(410U_TEST_OBJS) diff --git a/410user/libthrgrp/thrgrp.c b/410user/libthrgrp/thrgrp.c new file mode 100644 index 0000000..ecd124a --- /dev/null +++ b/410user/libthrgrp/thrgrp.c @@ -0,0 +1,201 @@ +/* @file thrgrp.c + * @brief This file contains the implementation of the wrapper for the + * thread library. This wrapper allows explicit control over what threads + * get joined on by what other threads. + * + * @author Matthew Brewer (mbrewer) + * + * The user allocates groups, and then initializes them. + * They can then spawn threads into these groups with thrgrp_create() + * When the threads exit (via returning.. NOT thr_exit()), they can be + * joined on using thrgrp_join(). A call to thrgrp_join() with group tg + * will reap any one thread to exit from that group, and then return. + */ + +#include <cond.h> +#include <thrgrp.h> +#include <thread.h> +#include <stddef.h> +#include <syscall.h> +#include <stdlib.h> +#include <stdio.h> +#include <simics.h> +#include <assert.h> + +/** + * @brief Initializes a thread group + * + * This function basically just initializes mutexes etc. + * + * @param eg An unitialized, but allocated, thread group to be initialized + * @return 0 on success, nonzero otherwise + * + * @pre thr_init should have been called + * @post eg is initialized + */ +int thrgrp_init_group(thrgrp_group_t *eg) { + int ret; + + eg->zombie_in = NULL; + eg->zombie_out = NULL; + if ((ret = mutex_init(&(eg->lock)))) + return ret; + if ((ret = cond_init(&(eg->cv)))) { + mutex_destroy(&(eg->lock)); + return ret; + } + return 0; +} + +/** + * @brief Destroys an initialized thrgroup + * + * Destroys the mutexes and other related stuff + * + * @param eg An initialized thread group to be destroyed + * @return 0 on success, nonzero otherwise + * + * @pre thrgrp_init_group(eg) has been called + * @post eg is uninitialized (but still allocated) + */ +int thrgrp_destroy_group(thrgrp_group_t *eg) { + int ret = 0; + + mutex_lock(&(eg->lock)); + + /* make sure that the queues are empty */ + if (eg->zombie_in || eg->zombie_out) + ret = 1; + + mutex_unlock(&(eg->lock)); + + if (ret == 0) { + mutex_destroy(&(eg->lock)); + cond_destroy(&(eg->cv)); + } + return ret; +} + +/** + * @brief Function to sit on the bottom of the thread stack + * + * @param in_data is a thrgrp_data_t, with tmp loaded with the function + * the user wants to run, the argument to call the function on, and + * the thread group this new thread is to be spawned in + * @return doesn't + */ +static void *thrgrp_bottom(void *in_data) { + thrgrp_data_t *data = (thrgrp_data_t *)in_data; + void *(*func)(void *) = data->tmp.func; + void *arg = data->tmp.arg; + thrgrp_group_t *tg = data->tmp.tg; + void *ret; + + /* now that we have all of the data out of data, + we'll use it as our queueing element */ + data->qel.next = NULL; + data->qel.tid = thr_getid(); + + /* run the code we were asked to run */ + ret = func(arg); + + /* insert ourselves into the zombie queue */ + mutex_lock(&(tg->lock)); + if (tg->zombie_in) + tg->zombie_in->next = &(data->qel); + tg->zombie_in = &(data->qel); + if (tg->zombie_out == NULL) + tg->zombie_out = &(data->qel); + + /* signal a waiter to come clean up our zombie */ + cond_signal(&(tg->cv)); + mutex_unlock(&(tg->lock)); + + /* if we return with ret, should exit with ret */ + return ret; +} + +/** @brief spawns a new thread in the thread group + * + * @param tg, an initialized thread group to spawn the new thread in + * @param func, function to run in the new thread + * @param arg, argument to pass the function to func + * @return 0 on success, nonzero otherwise + */ +int thrgrp_create(thrgrp_group_t *tg, void *(*func)(void *), void *arg) { + int tid; + thrgrp_data_t *data; + + /* setup a hunk of data + this is used both to get the arguments into the other thread, + and then as the memory to go on the zombie queue, this way we + malloc only once */ + data = malloc(sizeof(thrgrp_data_t)); + if (data == NULL) + return -1; + data->tmp.func = func; + data->tmp.arg = arg; + data->tmp.tg = tg; + + /* spawn the thread */ + tid = thr_create(thrgrp_bottom, data); + + /* tid < 0 indicates error */ + if (tid < 0) { + free(data); + return tid; + } + + /* we don't return the tid, because you're not supposed to join on it + must be joined with thrgrp_join(), not thr_join() */ + return 0; +} + +/** @brief joins on any thread in the group which exits + * + * like thr_join(), but will join on any exited thread which was spawned into + * this thread group via thrgrp_create() + * + * throughout this function thrgrp_queue_el_t is a LIE! in reality this is + * thrgrp_data_t, a union including thrgrp_queue_el_t as a subtype. this is + * only important because one should realize "free" is freeing thrgrp_data_t + * of memory, not thrgrp_queue_el_t of memory + * + * @param eg, an initialized thread group to join on threads in + * @param depared, a pointer to some memory, the TID of the exited + * thread will be placed here before thrgrp_join returns + * @param status, a pointer to a void *, where the return status of + * the thread we join on (i.e., what's returned from that thread's first function + * @return returns the result of thr_join + */ +int thrgrp_join(thrgrp_group_t *eg, void **status) { + thrgrp_queue_el_t *thr_data; + int tid; + + mutex_lock(&(eg->lock)); + /* check to see if there's someone to join on */ + while (eg->zombie_out == NULL) { + /* wait until there is someone to join on */ + cond_wait(&(eg->cv), &(eg->lock)); + /* inside of cond_wait, someone can sneek in + * i.e., even if condition variables are implemented in-order + * we do not have guaranteed in-order joins */ + } + + /* get our zombie from the queue */ + thr_data = eg->zombie_out; + if (eg->zombie_out == eg->zombie_in) { + eg->zombie_in = NULL; + eg->zombie_out = NULL; + } else { + eg->zombie_out = eg->zombie_out->next; + } + mutex_unlock(&(eg->lock)); + + /* grab the tid out before we free it */ + tid = thr_data->tid; + /* free the memory from the queue */ + free(thr_data); + /* join on the tid, and return the result */ + return thr_join(tid, status); +} diff --git a/410user/libthrgrp/thrgrp.h b/410user/libthrgrp/thrgrp.h new file mode 100644 index 0000000..73e9e2d --- /dev/null +++ b/410user/libthrgrp/thrgrp.h @@ -0,0 +1,71 @@ +/* @file thrgrp.h + * @brief This file defines the interface for the thread library wrapper. + * This wrapper allows explicit control over what exiting threads get joined + * on by what joining threads. + * @author Matthew Brewer (mbrewer) + */ + +#ifndef THRGRP_H +#define THRGRP_H +#include <cond.h> + +/** + * @brief This is an element of a thread group queue, used for storing + * exited threads. + */ +typedef struct thrgrp_queue_el { + /** @brief the next element in the queue */ + struct thrgrp_queue_el *next; + /** @brief the tid of the thread to exit */ + int tid; +} thrgrp_queue_el_t; + +/** + * @brief This is a structure holding information for joining and exiting + * threads. The idea is that threads exiting on this exitgroup can be joined + * on by threads joining on this exitgroup. + */ +typedef struct { + /* @brief a condition variable holding joiners waiting on exiters */ + cond_t cv; + /* @brief a list of zombie threads waiting to be reaped */ + thrgrp_queue_el_t *zombie_in; + thrgrp_queue_el_t *zombie_out; + /* @brief a mutex for protecting the rest of this data */ + mutex_t lock; +} thrgrp_group_t; + +/** + * @brief This is a temporary structure used for passing data into a spawned + * thread + */ +typedef struct thrgrp_tmp_data { + /** @brief function to call in newly spaned thread */ + void *(*func)(void *); + /** @brief argument to func */ + void *arg; + /** @brief thread group to spawn the new thread in */ + thrgrp_group_t *tg; +} thrgrp_tmp_data_t; + +/** + * @brief This is a union for malloc purposes, so it can be used for + * either a queue element, or temporary data, this way we only have to + * malloc once per thread spawn + */ +typedef union thrgrp_data { + /** @brief a queue element */ + thrgrp_queue_el_t qel; + /** @brief a temporary data structure */ + thrgrp_tmp_data_t tmp; +} thrgrp_data_t; + +int thrgrp_init_group(thrgrp_group_t *eg); + +int thrgrp_destroy_group(thrgrp_group_t *eg); + +int thrgrp_create(thrgrp_group_t *tg, void *(*func)(void *), void *args); + +int thrgrp_join(thrgrp_group_t *tg, void **status); + +#endif /* WRAPTH_H */ diff --git a/410user/libthrgrp/user.mk b/410user/libthrgrp/user.mk new file mode 100644 index 0000000..b35ea3a --- /dev/null +++ b/410user/libthrgrp/user.mk @@ -0,0 +1,7 @@ +410ULIB_THRGRP_OBJS := thrgrp.o +410ULIB_THRGRP_OBJS := $(410ULIB_THRGRP_OBJS:%=$(410UDIR)/libthrgrp/%) + +ALL_410UOBJS += $(410ULIB_THRGRP_OBJS) +410UCLEANS += $(410UDIR)/libthrgrp.a + +$(410UDIR)/libthrgrp.a: $(410ULIB_THRGRP_OBJS) diff --git a/410user/libx86/bcopy.S b/410user/libx86/bcopy.S new file mode 100644 index 0000000..f687231 --- /dev/null +++ b/410user/libx86/bcopy.S @@ -0,0 +1,135 @@ +/* + * Mach Operating System + * Copyright (c) 1992,1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#include <asm_style.h> + + +#if 0 /* is this useful? */ + +/* l2rbcopy(from, to, bcount) */ + +ENTRY(l2rbcopy) + pushl %ebp + movl %esp,%ebp + pushl %edi + pushl %esi + movl B_ARG2,%edx + movl B_ARG1,%edi + movl B_ARG0,%esi +/* move longs */ +0: cld + movl %edx,%ecx + sarl $2,%ecx + js 1f + rep + movsl +/* move bytes */ + movl %edx,%ecx + andl $3,%ecx + rep + movsb +1: + popl %esi + popl %edi + leave + ret +#endif + + + +/* + * bcopy - like l2rbcopy, but recognizes overlapping ranges and handles + * them correctly. + * bcopy(from, to, bytes) + * char *from, *to; + * int bytes; + */ +ENTRY(bcopy) + pushl %ebp + movl %esp,%ebp + pushl %edi + pushl %esi + movl B_ARG0,%esi + movl B_ARG1,%edi +bcopy_common: + movl B_ARG2,%edx + leal (%esi,%edx), %eax /* from + bytes */ + cmpl %eax, %edi /* <= to */ + jae 0f + leal (%edi,%edx), %eax /* to + bytes */ + cmpl %eax, %esi /* <= from */ + jae 0f + cmpl %esi, %edi /* from > to */ + jb 0f + je 1f + + addl %edx, %esi; decl %esi + addl %edx, %edi; decl %edi + std + movl %edx,%ecx +/* move bytes backwards */ + rep + movsb + cld +1: +/* memcpy: return dest pointer */ + movl B_ARG0,%eax + popl %esi + popl %edi + leave + ret +/* move words forwards */ +0: cld + movl %edx,%ecx + sarl $2,%ecx + js 2f + rep + movsl +/* move bytes forwards */ + movl %edx,%ecx + andl $3,%ecx + rep + movsb +2: +/* memcpy: return dest pointer */ + movl B_ARG0,%eax + popl %esi + popl %edi + leave + ret + +/* memcpy(to, from, count) */ + +ENTRY(memcpy) +ENTRY(memmove) + pushl %ebp + movl %esp,%ebp + pushl %edi + pushl %esi + movl B_ARG0,%edi + movl B_ARG1,%esi + jmp bcopy_common + diff --git a/410user/libx86/bzero.S b/410user/libx86/bzero.S new file mode 100644 index 0000000..6675745 --- /dev/null +++ b/410user/libx86/bzero.S @@ -0,0 +1,47 @@ +/* + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + */ + +#include <asm_style.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: bzero.S,v 1.8 1995/04/28 22:57:58 jtc Exp $") +#endif + + +ENTRY(bzero) + pushl %edi + movl S_ARG1,%edi + movl S_ARG2,%edx + + cld /* set fill direction forward */ + xorl %eax,%eax /* set fill data to 0 */ + + /* + * if the string is too short, it's really not worth the overhead + * of aligning to word boundries, etc. So we jump to a plain + * unaligned set. + */ + cmpl $16,%edx + jb L1 + + movl %edi,%ecx /* compute misalignment */ + negl %ecx + andl $3,%ecx + subl %ecx,%edx + rep /* zero until word aligned */ + stosb + + movl %edx,%ecx /* zero by words */ + shrl $2,%ecx + andl $3,%edx + rep + stosl + +L1: movl %edx,%ecx /* zero remainder by bytes */ + rep + stosb + + popl %edi + ret diff --git a/410user/libx86/gccisms.c b/410user/libx86/gccisms.c new file mode 100644 index 0000000..fea7c5b --- /dev/null +++ b/410user/libx86/gccisms.c @@ -0,0 +1,346 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ------------ + * + * Lovingly ripped, slashed, mangled, and mutilated into one file by nwf@, + * 20080814 to fit inside the CS410 universe; in some places this has resulted + * in very carefully constructed, portable code becoming x86 specific. Sorry. + * + * Taken from ftp://ftp.openbsd.org/pub/OpenBSD/3.9/sys.tar.gz + */ + +#define HALF_BITS (sizeof(int)*8/2) +#define B ((int)1 << HALF_BITS) /* digit base */ +#define H 1 /* Endianness matters */ +#define L 0 + +/* + * Extract high and low shortwords from longword, and move low shortword of + * longword to upper half of long, i.e., produce the upper longword of + * ((quad_t)(x) << (number_of_bits_in_int/2)). (`x' must actually be u_int.) + * + * These are used in the multiply code, to split a longword into upper + * and lower halves, and to reassemble a product as a quad_t, shifted left + * (sizeof(int)*CHAR_BIT/2). + */ +#define HHALF(x) ((u_int)(x) >> HALF_BITS) +#define LHALF(x) ((u_int)(x) & (((int)1 << HALF_BITS) - 1)) + +typedef unsigned int u_int; + +typedef u_int digit; +typedef long long quad_t; /* 64 bits, signed */ +typedef unsigned long long u_quad_t; /* 64 bits, unsigned */ + +/* + * Depending on the desired operation, we view a `long long' (aka quad_t) in + * one or more of the following formats. + */ +union uu { + quad_t q; /* as a (signed) quad */ + u_quad_t uq; /* as an unsigned quad */ + int sl[2]; /* as two signed ints */ + u_int ul[2]; /* as two unsigned ints */ +}; + +/* Combine two `digits' to make a single two-digit number. */ +#define COMBINE(a, b) (((u_int)(a) << HALF_BITS) | (b)) + + +static void shl(digit *p, int len, int sh); + +/* + * __qdivrem(u, v, rem) returns u/v and, optionally, sets *rem to u%v. + * + * We do this in base 2-sup-HALF_BITS, so that all intermediate products + * fit within u_int. As a consequence, the maximum length dividend and + * divisor are 4 `digits' in this base (they are shorter if they have + * leading zeros). + */ +u_quad_t +__qdivrem(u_quad_t uq, u_quad_t vq, u_quad_t *arq) +{ + union uu tmp; + digit *u, *v, *q; + digit v1, v2; + u_int qhat, rhat, t; + int m, n, d, j, i; + digit uspace[5], vspace[5], qspace[5]; + + /* + * Take care of special cases: divide by zero, and u < v. + */ + if (vq == 0) { + /* divide by zero. */ + static volatile const unsigned int zero = 0; + + tmp.ul[H] = tmp.ul[L] = 1 / zero; + if (arq) + *arq = uq; + return (tmp.q); + } + if (uq < vq) { + if (arq) + *arq = uq; + return (0); + } + u = &uspace[0]; + v = &vspace[0]; + q = &qspace[0]; + + /* + * Break dividend and divisor into digits in base B, then + * count leading zeros to determine m and n. When done, we + * will have: + * u = (u[1]u[2]...u[m+n]) sub B + * v = (v[1]v[2]...v[n]) sub B + * v[1] != 0 + * 1 < n <= 4 (if n = 1, we use a different division algorithm) + * m >= 0 (otherwise u < v, which we already checked) + * m + n = 4 + * and thus + * m = 4 - n <= 2 + */ + tmp.uq = uq; + u[0] = 0; + u[1] = (digit)HHALF(tmp.ul[H]); + u[2] = (digit)LHALF(tmp.ul[H]); + u[3] = (digit)HHALF(tmp.ul[L]); + u[4] = (digit)LHALF(tmp.ul[L]); + tmp.uq = vq; + v[1] = (digit)HHALF(tmp.ul[H]); + v[2] = (digit)LHALF(tmp.ul[H]); + v[3] = (digit)HHALF(tmp.ul[L]); + v[4] = (digit)LHALF(tmp.ul[L]); + for (n = 4; v[1] == 0; v++) { + if (--n == 1) { + u_int rbj; /* r*B+u[j] (not root boy jim) */ + digit q1, q2, q3, q4; + + /* + * Change of plan, per exercise 16. + * r = 0; + * for j = 1..4: + * q[j] = floor((r*B + u[j]) / v), + * r = (r*B + u[j]) % v; + * We unroll this completely here. + */ + t = v[2]; /* nonzero, by definition */ + q1 = (digit)(u[1] / t); + rbj = COMBINE(u[1] % t, u[2]); + q2 = (digit)(rbj / t); + rbj = COMBINE(rbj % t, u[3]); + q3 = (digit)(rbj / t); + rbj = COMBINE(rbj % t, u[4]); + q4 = (digit)(rbj / t); + if (arq) + *arq = rbj % t; + tmp.ul[H] = COMBINE(q1, q2); + tmp.ul[L] = COMBINE(q3, q4); + return (tmp.q); + } + } + + /* + * By adjusting q once we determine m, we can guarantee that + * there is a complete four-digit quotient at &qspace[1] when + * we finally stop. + */ + for (m = 4 - n; u[1] == 0; u++) + m--; + for (i = 4 - m; --i >= 0;) + q[i] = 0; + q += 4 - m; + + /* + * Here we run Program D, translated from MIX to C and acquiring + * a few minor changes. + * + * D1: choose multiplier 1 << d to ensure v[1] >= B/2. + */ + d = 0; + for (t = v[1]; t < B / 2; t <<= 1) + d++; + if (d > 0) { + shl(&u[0], m + n, d); /* u <<= d */ + shl(&v[1], n - 1, d); /* v <<= d */ + } + /* + * D2: j = 0. + */ + j = 0; + v1 = v[1]; /* for D3 -- note that v[1..n] are constant */ + v2 = v[2]; /* for D3 */ + do { + digit uj0, uj1, uj2; + + /* + * D3: Calculate qhat (\^q, in TeX notation). + * Let qhat = min((u[j]*B + u[j+1])/v[1], B-1), and + * let rhat = (u[j]*B + u[j+1]) mod v[1]. + * While rhat < B and v[2]*qhat > rhat*B+u[j+2], + * decrement qhat and increase rhat correspondingly. + * Note that if rhat >= B, v[2]*qhat < rhat*B. + */ + uj0 = u[j + 0]; /* for D3 only -- note that u[j+...] change */ + uj1 = u[j + 1]; /* for D3 only */ + uj2 = u[j + 2]; /* for D3 only */ + if (uj0 == v1) { + qhat = B; + rhat = uj1; + goto qhat_too_big; + } else { + u_int nn = COMBINE(uj0, uj1); + qhat = nn / v1; + rhat = nn % v1; + } + while (v2 * qhat > COMBINE(rhat, uj2)) { + qhat_too_big: + qhat--; + if ((rhat += v1) >= B) + break; + } + /* + * D4: Multiply and subtract. + * The variable `t' holds any borrows across the loop. + * We split this up so that we do not require v[0] = 0, + * and to eliminate a final special case. + */ + for (t = 0, i = n; i > 0; i--) { + t = u[i + j] - v[i] * qhat - t; + u[i + j] = (digit)LHALF(t); + t = (B - HHALF(t)) & (B - 1); + } + t = u[j] - t; + u[j] = (digit)LHALF(t); + /* + * D5: test remainder. + * There is a borrow if and only if HHALF(t) is nonzero; + * in that (rare) case, qhat was too large (by exactly 1). + * Fix it by adding v[1..n] to u[j..j+n]. + */ + if (HHALF(t)) { + qhat--; + for (t = 0, i = n; i > 0; i--) { /* D6: add back. */ + t += u[i + j] + v[i]; + u[i + j] = (digit)LHALF(t); + t = HHALF(t); + } + u[j] = (digit)LHALF(u[j] + t); + } + q[j] = (digit)qhat; + } while (++j <= m); /* D7: loop on j. */ + + /* + * If caller wants the remainder, we have to calculate it as + * u[m..m+n] >> d (this is at most n digits and thus fits in + * u[m+1..m+n], but we may need more source digits). + */ + if (arq) { + if (d) { + for (i = m + n; i > m; --i) + u[i] = (digit)(((u_int)u[i] >> d) | + LHALF((u_int)u[i - 1] << (HALF_BITS - d))); + u[i] = 0; + } + tmp.ul[H] = COMBINE(uspace[1], uspace[2]); + tmp.ul[L] = COMBINE(uspace[3], uspace[4]); + *arq = tmp.q; + } + + tmp.ul[H] = COMBINE(qspace[1], qspace[2]); + tmp.ul[L] = COMBINE(qspace[3], qspace[4]); + return (tmp.q); +} + +/* + * Shift p[0]..p[len] left `sh' bits, ignoring any bits that + * `fall out' the left (there never will be any such anyway). + * We may assume len >= 0. NOTE THAT THIS WRITES len+1 DIGITS. + */ +static void +shl(digit *p, int len, int sh) +{ + int i; + + for (i = 0; i < len; i++) + p[i] = (digit)(LHALF((u_int)p[i] << sh) | + ((u_int)p[i + 1] >> (HALF_BITS - sh))); + p[i] = (digit)(LHALF((u_int)p[i] << sh)); +} + + +/* + * Return remainder after dividing two unsigned quads. + */ +u_quad_t +__umoddi3(u_quad_t a, u_quad_t b) +{ + u_quad_t r; + + (void)__qdivrem(a, b, &r); + return (r); +} + +/* + * Divide two unsigned quads. + */ +u_quad_t +__udivdi3(u_quad_t a, u_quad_t b) +{ + + return (__qdivrem(a, b, (u_quad_t *)0)); +} + +/* + * Divide two signed quads. + * ??? if -1/2 should produce -1 on this machine, this code is wrong + */ +quad_t +__divdi3(quad_t a, quad_t b) +{ + u_quad_t ua, ub, uq; + int neg = 0; + + ua = a; + ub = b; + + if (a < 0) + ua = -ua, neg ^= 1; + if (b < 0) + ub = -ub, neg ^= 1; + + uq = __qdivrem(ua, ub, (u_quad_t *)0); + if (neg) + uq = - uq; + return uq; +} diff --git a/410user/libx86/user.mk b/410user/libx86/user.mk new file mode 100644 index 0000000..a583822 --- /dev/null +++ b/410user/libx86/user.mk @@ -0,0 +1,11 @@ +410U_X86_OBJS := \ + bcopy.o \ + bzero.o \ + gccisms.o \ + +410U_X86_OBJS := $(410U_X86_OBJS:%=$(410UDIR)/libx86/%) + +ALL_410UOBJS += $(410U_X86_OBJS) +410UCLEANS += $(410UDIR)/libx86.a + +$(410UDIR)/libx86.a: $(410U_X86_OBJS) diff --git a/410user/progs/ack.c b/410user/progs/ack.c new file mode 100644 index 0000000..2375ad9 --- /dev/null +++ b/410user/progs/ack.c @@ -0,0 +1,56 @@ +/** @file 410user/progs/ack.c + * @author acrichto + * @brief Computes Ackermann function in multiple threads + * @public yes + * @for p4-smp + * @status done + */ + +/* "Because not all total computable functions are primitive recursive" */ + +#include <thread.h> +#include <thrgrp.h> +#include <410_tests.h> +#include <stdio.h> +#include <syscall.h> + +DEF_TEST_NAME("ack:"); + +#define ACKN 8 +#define THREADS 8 + +typedef void*(thr_func)(void*); + +int ack(int m, int n) { + if (m == 0) return n + 1; + if (n == 0) return ack(m - 1, 1); + return ack(m - 1, ack(m, n - 1)); +} + +void* ackstart(void *n) { + return (void*) ack(3, (int) n); +} + +int main() { + thr_init(1024 * 128); + int ticks = get_ticks(); + int i, answer, guess; + thrgrp_group_t group; + + REPORT_ON_ERR(thrgrp_init_group(&group)); + for (i = 0; i < THREADS; i++) { + REPORT_ON_ERR(thrgrp_create(&group, (thr_func*) ackstart, (void*) ACKN)); + } + + REPORT_ON_ERR(thrgrp_join(&group, (void*) &answer)); + for (i = 1; i < THREADS; i++) { + REPORT_ON_ERR(thrgrp_join(&group, (void*) &guess)); + if (guess != answer) { + REPORT_END_FAIL; + } + } + printf("ack(3, %d) = %d\n", ACKN, answer); + printf("ticks taken: %d\n", get_ticks() - ticks); + + thr_exit(0); +} diff --git a/410user/progs/actual_wait.c b/410user/progs/actual_wait.c new file mode 100644 index 0000000..983ddb2 --- /dev/null +++ b/410user/progs/actual_wait.c @@ -0,0 +1,131 @@ +/** @file 410user/progs/actual_wait.c + * @author de0u + * @brief Exercises wait() and vanish(). + * @public yes + * @for p2 p3 + * @covers wait vanish fork yield set_status + * @status done + */ + +#include <syscall.h> +#include <stdlib.h> +#include <stdio.h> +#include <simics.h> + +#include "410_tests.h" +DEF_TEST_NAME("actual_wait:"); + +#define NCHILD 40 /* must be < 255 */ +#define PRESERVE (1024*1024) + +void child(int); + +int main(void) +{ + char buf[4096]; + int pid, pids[NCHILD]; + int c, preserve; + char msg[128]; + + buf[0] = buf[sizeof (buf) - 1] = 'q'; + + REPORT_START_CMPLT; + + for (c = 0; c < NCHILD; ++c) + switch(((pid = fork()) < 0) ? -1 : pid) { + case -1: + REPORT_MISC("cannot fork"); + goto fail; + case 0: + child(c); + break; + default: + pids[c] = pid; + + snprintf(msg, sizeof (msg), "slot %d pid %d", c, pid); + printf("%s\n", msg); + REPORT_MISC(msg); + + if (c & 1) + yield(-1); + break; + } + + for (c = 0; c < NCHILD; ++c) { + int slot; + char msg[128]; + + if ((c & 8) == 8) + yield(-1); + + pid = wait(&slot); + + snprintf(msg, sizeof (msg), "slot %d pid %d", slot, pid); + printf("%s\n", msg); + REPORT_MISC(msg); + + if ((slot < 0) || (slot >= NCHILD)) { + REPORT_MISC("invalid slot"); + goto fail; + } + if (pids[slot] != pid) { + REPORT_MISC("pid/slot mismatch"); + goto fail; + } + pids[slot] = -1; + } + + preserve = PRESERVE; + pid = wait(&preserve); + if (pid >= 0) { + REPORT_MISC("phantom menace"); + goto fail; + } + if (preserve != PRESERVE) { + REPORT_MISC("obliteration"); + goto fail; + } + + REPORT_END_SUCCESS; + exit(0); + +fail: + REPORT_END_FAIL; + exit(9); +} + +void +child(int which) +{ + int wpid, gpid; + char msg[128]; + + snprintf(msg, sizeof (msg), "child %d", which); + printf("%s\n", msg); + REPORT_MISC(msg); + + switch(((gpid = fork()) < 0) ? -1 : gpid) { + case -1: + REPORT_MISC("child cannot fork"); + goto fail; + break; + case 0: + if (which & 1) { + yield(-1); + yield(-1); + } + exit(0); + default: + if ((which & 4) != 4) { + if ((wpid = wait(0)) != gpid) { + REPORT_MISC("grandchild??"); + goto fail; + } + } + exit(which); + break; + } + +fail: + exit(-1); +} diff --git a/410user/progs/bg.c b/410user/progs/bg.c new file mode 100644 index 0000000..feccf37 --- /dev/null +++ b/410user/progs/bg.c @@ -0,0 +1,39 @@ +/** @file 410user/progs/bg.c + * @author mjsulliv (2009) + * @brief runs a command in the background + * @public yes + * @for p3,p4 + * @covers fork + * @bug This should arguably be done by the shell. + */ + +#include <syscall.h> +#include <stdio.h> +#include <assert.h> + +int main(int argc, char *argv[]) +{ + int pid; + + if (argv[argc]) printf("*** fsck: %p!\n", argv[argc]); + + if (argc < 2) { + printf("usage: %s program [arguments]\n", argv[0]); + return 1; + } + + if ((pid = fork()) > 0) { + printf("Child pid: %d\n", pid); + return 0; + } else if (pid < 0) { + return 1; + } + + /* Now we are a child, our parent is exiting, so we will be owned by init. + * The shell was waiting on our parent and doesn't give a hoot about us. */ + + int ret = exec(argv[1], &argv[1]); + panic("exec failed: %d!", ret); + + return 0; +} diff --git a/410user/progs/bistromath.c b/410user/progs/bistromath.c new file mode 100644 index 0000000..9b63047 --- /dev/null +++ b/410user/progs/bistromath.c @@ -0,0 +1,7711 @@ +/****************************************************************************** + * This is a port of the chess engine "bistromath" to the Pebbles kernel. + * Both the original and the port are copyright Ben Blum <bblum@andrew.cmu.edu> + * 2013, all rights reserved. + * + * Readers interested in the inner workings of the chess engine will be much + * happier navigating the original codebase, where the files are not all + * concatenated together. + * + * ====> http://bblum.net/bistromath.tar.bz2 <==== + * + * The pebbles glue / console interface (which are obviously not present in the + * original version) are at the bottom of this file, around line 7050. + * + * This program incidentally tests for the following Pebbles functionalities: + * - Loading very large ELFs (.bss comes out to be about 192MB) + * - Stack growth (each ply searched takes a little over 32KB of stack) + * - Simple threading -- another thread is used for the search timer + * + * Please direct all questions/bugs to Ben Blum <bblum@andrew.cmu.edu>. + * + ****************************************************************************** + * + * This code is licensed under the GNU Library GPL: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + ******************************************************************************/ + +#include <syscall.h> +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <assert.h> +#include <stdio.h> +#include <stdint.h> + +#include "rand.h" +#include "thread.h" + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) ((sizeof(a))/(sizeof(a[0]))) +#endif + +/**************************************************************************** + * attacks.h - precomputed attack-/move-mask tables + * copyright (C) 2008 Ben Blum + ****************************************************************************/ +#ifndef ATTACKS_H +#define ATTACKS_H + +#define U64(x) ((uint64_t)(x ## ull)) +#define U32(x) ((uint32_t)(x)) + +extern uint64_t knightattacks[64]; +extern uint64_t kingattacks[64]; +extern uint64_t pawnattacks[2][64]; +extern uint64_t pawnmoves[2][64]; + +extern uint64_t rowattacks[256][8]; +extern uint64_t colattacks[256][8]; + +extern int rot45diagindex[64]; +extern int rot315diagindex[64]; + +extern int rot45index_shiftamountright[15]; +extern int rot315index_shiftamountright[15]; +extern int rot315index_shiftamountleft[15]; + +extern int rotresult_shiftamountleft[15]; +extern int rotresult_shiftamountright[15]; + +uint64_t rot45attacks[256][8]; +uint64_t rot315attacks[256][8]; + +#endif +/**************************************************************************** + * bitscan.h - useful for switching bitscan implementations + * copyright (C) 2008 Ben Blum + ****************************************************************************/ +#ifndef BITSCAN_H +#define BITSCAN_H + +#define BITSCAN(x) (ffsll(x)-1) + +#endif + +// Below are ffs.c and ffsll.c from a standard glibc distribution, since 410user +// doesn't have them. + +/* Copyright (C) 1991, 1992, 1997, 1998, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Torbjorn Granlund (tege@sics.se). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#define ffs(x) __ffs(x) + +/* Find the first bit set in I. */ +int +__ffs (i) + int i; +{ + static const unsigned char table[] = + { + 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 + }; + unsigned int a; + unsigned int x = i & -i; + + a = x <= 0xffff ? (x <= 0xff ? 0 : 8) : (x <= 0xffffff ? 16 : 24); + + return table[x >> a] + a; +} +/* Copyright (C) 1991, 1992, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Torbjorn Granlund (tege@sics.se). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +/* Find the first bit set in I. */ +int +ffsll (i) + long long int i; +{ + unsigned long long int x = i & -i; + + if (x <= 0xffffffff) + return ffs (i); + else + return 32 + ffs (i >> 32); +} + +/**************************************************************************** + * popcnt.h - various population-count implementations + * copyright (C) 2008 Ben Blum + ****************************************************************************/ +#ifndef POPCNT_H +#define POPCNT_H + +/* Can be used to change which implementation we use */ +//#define POPCOUNT(x) popcnt3(x) +#define POPCOUNT(x) popcnt2(x) + +/** + * Returns a count of how many bits are set in the argument. + */ +int popcnt(uint64_t); + +/** + * Alternative implementations + */ +int popcnt2(uint64_t); +int popcnt3(uint64_t); + +#endif +/**************************************************************************** + * rand.h - wrappers for random number generation utilities + * copyright (C) 2008 Ben Blum + ****************************************************************************/ + +/* Set up the random number generator */ +void rand_init(); +/* A "random" 32-bit integer as provided by GSL's mersenne twister */ +uint32_t rand32(); +/* A "random" 64-bit integer as provided by GSL's mersenne twister */ +uint64_t rand64(); + +/**************************************************************************** + * movelist.h - data structure for move sorting in move generation/iteration + * copyright (C) 2008 Ben Blum + * ****************************************************************************/ +#ifndef MOVELIST_H +#define MOVELIST_H + + +#define MOVELIST_NUM_BUCKETS 64 +#define MOVELIST_SUBLIST_LENGTH 128 + +/**************************************************************************** + * Our move ordering scheme will look something like this: + * + * 00-08: Moves that lose material + * 00: -9 (Q hang) + * 01: -8 (Qx protected P) + * 02: -7 (None) + * 03: -6 (Qx protected B/N) + * 04: -5 (R hang) + * 05: -4 (Qx protected R) + * 06: -3 (B/N hang) + * 07: -2 (Bx/Nx protected P, Rx protected B/N) + * 08: -1 (P hang) + * 9-41: Regular moves, indexed by piecetable[dest] - piecetable[src] + 25 + * 42: Minor promotions + * 43: O-O-O + * 44: O-O + * 45-49: Neutral captures + * 45: PxP + * 46: NxN + * 47: BxB + * 48: RxR + * 49: QxQ + * 50-58: Moves that win material + * 50: +1 (P unhang, *x hung P) + * 51: +2 (Px protected B/N, Bx/Nx protected R) + * 52: +3 (B/N unhang, *x hung B/N) + * 53: +4 (Px protected R) + * 54: +5 (R unhang, *x hung B/N) + * 55: +6 (Bx/Nx protected Q) + * 56: +7 (None) + * 57: +8 (Px protected Q) + * 58: +9 (Q unhang, *x hung Q) + * 59: Promotions to queen + * 60: Promotions to queen with capture + * 61: K unhang + ****************************************************************************/ + +/* starting index for moves that lose material - subtract how much is lost */ +#define MOVELIST_INDEX_MAT_LOSS 9 +/* regular move - add the piece/square table difference */ +#define MOVELIST_INDEX_REGULAR 25 +/* minor promotion - the thought behind this is if the Q promotion is wrong, + * probably this will be too, so try other moves first */ +#define MOVELIST_INDEX_PROM_MINOR 42 +/* castle - add 1 if kingside */ +#define MOVELIST_INDEX_CASTLE 43 +/* neutral capture - add the piece number (P=0 ... Q=4) */ +#define MOVELIST_INDEX_NEUTRAL 45 +/* moves that win material - add how much is gained */ +#define MOVELIST_INDEX_MAT_GAIN 49 +/* promotion to queen - add one if it's also a capture */ +#define MOVELIST_INDEX_PROM_QUEEN 59 + +/** + * The movelist_t data structure is a generalization of maintaining multiple + * linkedlists and appending them at the end for O(n) pseudo-sorting - it + * allows an arbitrary number of lists for sorting into that many buckets, + * with the only constraints being 1) space and 2) time to move the "max" + * index to point to the next bucket when one bucket is empty. The result is + * O(n) sorting during creation (beating O(n^2 logn)), but an additional O(m) + * coefficient for both space and time complexity, so choose a small m! + */ +typedef struct { + uint32_t array[MOVELIST_NUM_BUCKETS][MOVELIST_SUBLIST_LENGTH]; + int sublist_count[MOVELIST_NUM_BUCKETS]; + /* highest index of a bucket which contains elements; note, if + * array[max] is empty, that means the whole movelist is empty */ + unsigned long max; +} movelist_inner_t; + +typedef movelist_inner_t *movelist_t; + +/* Movelist's max should be zero, each array should be zero, and each +* array should have a count of zero. */ +static inline void movelist_init(movelist_t *ml) +{ + *ml = malloc(sizeof(movelist_inner_t)); + affirm_msg(*ml, "Couldn't allocate memory to generate moves"); + memset((*ml)->sublist_count, 0, MOVELIST_NUM_BUCKETS*sizeof(int)); + (*ml)->max = 0; +} + +#define movelist_destroy(mlp) do { free(*mlp); } while (0) + +void movelist_add(movelist_t *, uint64_t[2], uint32_t); +void movelist_addtohead(movelist_t *, uint32_t, unsigned long); +int movelist_isempty(movelist_t *); +uint32_t movelist_remove_max(movelist_t *); + +#endif + +/**************************************************************************** + * board.h - rotated bitboard library; move generation and board state + * copyright (C) 2008 Ben Blum + ****************************************************************************/ +#ifndef BOARD_H +#define BOARD_H + +/** + * Piece/color constants. Used as indices to get the position bitboard of a + * given piece of a given color, among other things. + */ +#define WHITE 0 +#define BLACK 1 + +/* The color not thise one. Equivalent to "x == WHITE ? BLACK : WHITE" */ +#define OTHERCOLOR(x) (1^(x)) +/* This player's home-rank (0 for white, 7 for black) */ +#define HOMEROW(x) ((x == WHITE) ? 0 : 7) + +/* Piece types */ +#define PAWN 0x0 +#define KNIGHT 0x1 +#define BISHOP 0x2 +#define ROOK 0x3 +#define QUEEN 0x4 +#define KING 0x5 +#define PIECE_SLIDES(p) (((p) > KNIGHT) && ((p) < KING)) +typedef uint8_t piece_t; + +extern char *piecename[2][6]; + +/** + * Square constants. 6 lowest bits: |0|0|r|o|w|c|o|l| + * These can serve as indexes to get bits out of a bitboard. Also used to get + * masks for sliding pieces by row/etc + */ +#define A1 0x00 +#define B1 0x01 +#define C1 0x02 +#define D1 0x03 +#define E1 0x04 +#define F1 0x05 +#define G1 0x06 +#define H1 0x07 +#define A2 0x08 +#define B2 0x09 +#define C2 0x0a +#define D2 0x0b +#define E2 0x0c +#define F2 0x0d +#define G2 0x0e +#define H2 0x0f +#define A3 0x10 +#define B3 0x11 +#define C3 0x12 +#define D3 0x13 +#define E3 0x14 +#define F3 0x15 +#define G3 0x16 +#define H3 0x17 +#define A4 0x18 +#define B4 0x19 +#define C4 0x1a +#define D4 0x1b +#define E4 0x1c +#define F4 0x1d +#define G4 0x1e +#define H4 0x1f +#define A5 0x20 +#define B5 0x21 +#define C5 0x22 +#define D5 0x23 +#define E5 0x24 +#define F5 0x25 +#define G5 0x26 +#define H5 0x27 +#define A6 0x28 +#define B6 0x29 +#define C6 0x2a +#define D6 0x2b +#define E6 0x2c +#define F6 0x2d +#define G6 0x2e +#define H6 0x2f +#define A7 0x30 +#define B7 0x31 +#define C7 0x32 +#define D7 0x33 +#define E7 0x34 +#define F7 0x35 +#define G7 0x36 +#define H7 0x37 +#define A8 0x38 +#define B8 0x39 +#define C8 0x3a +#define D8 0x3b +#define E8 0x3c +#define F8 0x3d +#define G8 0x3e +#define H8 0x3f +typedef uint8_t square_t; + +/* Converts int to string. Better than using malloc for 3-length strings. */ +extern char *squarename[64]; + +#define RANK_1 0 +#define RANK_2 1 +#define RANK_3 2 +#define RANK_4 3 +#define RANK_5 4 +#define RANK_6 5 +#define RANK_7 6 +#define RANK_8 7 +#define COL_A 0 +#define COL_B 1 +#define COL_C 2 +#define COL_D 3 +#define COL_E 4 +#define COL_F 5 +#define COL_G 6 +#define COL_H 7 + +/* converting square <--> (column,row) */ +#define COL(s) ((s) & 0x7) /* 0<=s<64 */ +#define ROW(s) ((s) >> 3) /* 0<=s<64 */ +#define SQUARE(c,r) ((square_t)((c) | ((r) << 3))) /* 0<=c,r<8 */ +/* what color is the square - 1 or 0, not necessarily BLACK or WHITE */ +#define PARITY(s) ((COL(s) + ROW(s)) & 0x1) + +/* Used mostly as array indices, especially for castling */ +#define QUEENSIDE 0 +#define KINGSIDE 1 +/* Given the side of the board, which column will the king end up on */ +#define CASTLE_DEST_COL(x) (((x) == QUEENSIDE) ? COL_C : COL_G) + +/* Constants for board_mated return values */ +#define BOARD_CHECKMATED 1 +#define BOARD_STALEMATED 2 + +/** + * move_t will contain a src square (lowest 6 bits), a dest square (next 6 + * bits), and several flags - is check, isenpassant, iscapture (and what + * piece type is captured), ispromotion (and what is promoted to), and + * also which color made the move. + * 000000 JJJ III HHH G F E D C BBBBBB AAAAAA + * 26 23 20 17 16 15 14 13 12 6 0 + * A: Source square + * B: Dest square + * C: Color (which side is making this move) + * D: Castle + * E: En passant + * F: Capture + * G: Promotion + * H: Captured piece type (color will be the opposite of C) + * I: Promotion result piece type (color indicated by C) + * J: Which piece type is moving (color indicated by C) + * 0: Unused bits + * Note: Bits 25 and up are used for the repetition count in the transposition + * table; see transposition.{h,c} + */ +typedef uint32_t move_t; +#define MOV_INDEX_SRC 0 +#define MOV_INDEX_DEST 6 +#define MOV_INDEX_COLOR 12 +#define MOV_INDEX_CASTLE 13 +#define MOV_INDEX_EP 14 +#define MOV_INDEX_CAPT 15 +#define MOV_INDEX_PROM 16 +#define MOV_INDEX_CAPTPC 17 +#define MOV_INDEX_PROMPC 20 +#define MOV_INDEX_PIECE 23 +#define MOV_INDEX_UNUSED 26 + +#define MOV_SRC(m) ((square_t)(((m) >> MOV_INDEX_SRC) & 0x3f)) +#define MOV_DEST(m) ((square_t)(((m) >> MOV_INDEX_DEST) & 0x3f)) +#define MOV_COLOR(m) (((m) >> MOV_INDEX_COLOR) & 0x1) +#define MOV_CASTLE(m) (((m) >> MOV_INDEX_CASTLE) & 0x1) +#define MOV_EP(m) (((m) >> MOV_INDEX_EP) & 0x1) +#define MOV_CAPT(m) (((m) >> MOV_INDEX_CAPT) & 0x1) +#define MOV_PROM(m) (((m) >> MOV_INDEX_PROM) & 0x1) +#define MOV_CAPTPC(m) ((piece_t)(((m) >> MOV_INDEX_CAPTPC) & 0x7)) +#define MOV_PROMPC(m) ((piece_t)(((m) >> MOV_INDEX_PROMPC) & 0x7)) +#define MOV_PIECE(m) ((piece_t)(((m) >> MOV_INDEX_PIECE) & 0x7)) + +/** + * 64-bit representation of a board's state for one set of piece, also used + * for representing attacks, regions of the board, ... + */ +typedef uint64_t bitboard_t; + +/** + * Zobrist hash key + */ +typedef uint64_t zobrist_t; + +/* Upper bound on how many halfmoves a game should take. Memory is cheap. */ +#define HISTORY_STACK_SIZE 2048 + +/** + * Nonrecomputable state stored on the history stack when a move is made + */ +typedef struct { + zobrist_t hash; + bitboard_t attackedby[2]; + unsigned char castle[2][2]; + square_t ep; + unsigned char halfmoves; + unsigned char reps; + move_t move; +} history_t; + +/**************************************************************************** + * Representation of an entire board state. + * The pos[][] array represents standard normal-oriented setups, accessed by + * piece and color. Normally oriented bitboards look like this: + * + * (64-bit format by square) + * H8 G8 F8 E8 D8 C8 B8 A8 H7 G7 ... A2 H1 G1 F1 E1 D1 C1 B1 A1 + * 63 62 61 60 59 58 57 56 55 54 ... 8 7 6 5 4 3 2 1 0 + * + * (8x8 format by index (from the least significant bit)) + * ------------------------- + * 8 | 56 57 58 59 60 61 62 63 | + * 7 | ... 54 55 | + * | ... | + * 3 | 16 17 ... | + * 2 | 8 9 10 11 12 13 14 15 | + * 1 | 0 1 2 3 4 5 6 7 | + * ------------------------- + * a b c d e f g h + * + * The n-th index row (0 for 1, 7 for 8) can be extracted by + * "(bitboard >> (8*n)) & 0xFF". The rotated boards are slightly different. + * Rot90, used for rook attacks, looks like this: + * + * H8 H7 H6 H5 H4 H3 H2 H1 G8 G7 ... B1 A8 A7 A6 A5 A4 A3 A2 A1 + * 63 62 61 60 59 58 57 56 55 54 ... 8 7 6 5 4 3 2 1 0 + * + * ------------------------- + * h | 56 57 58 59 60 61 62 63 | + * g | ... 54 55 | + * | ... | + * c | 16 17 ... | + * b | 8 9 10 11 12 13 14 15 | + * a | 0 1 2 3 4 5 6 7 | + * ------------------------- + * 1 2 3 4 5 6 7 8 + * + * So the n-th index file (0 for a, 7 for h) can be obtained easily. Note that + * "rot90" is a lie, it's actually flipped across the a1-h8 diagonal. For + * bishops, we rotate so squares on a single diagonal are adjacent. + * rot45: rot315: + * ,--, 8 ,--, + * ,' 63 ', 7 ,' 63 ', + * ,' 61 62 ', 6 ,' 61 62 ', + * ,' 58 59 60 ', 5 ,' 58 59 60 ', + * ,' 54 55 56 57 ', 4 ,' 54 55 56 57 ', + * ,' 49 50 51 52 53 ', 3 ,' 49 50 51 52 53 ', + * ,' 43 44 45 46 47 48 ', 2 ,' 43 44 45 46 47 48 ', + * ,' 36 37 38 39 40 41 42 ', 1 ,' 36 37 38 39 40 41 42 ', + * ( 28 29 30 31 32 33 34 35 ) ( 28 29 30 31 32 33 34 35 ) + * 8 ', 21 22 23 24 25 26 27 ,' h a ', 21 22 23 24 25 26 27 ,' + * 7 ', 15 16 17 18 19 20 ,' g b ', 15 16 17 18 19 20 ,' + * 6 ', 10 11 12 13 14 ,' f c ', 10 11 12 13 14 ,' + * 5 ', 06 07 08 09 ,' e d ', 06 07 08 09 ,' + * 4 ', 03 04 05 ,' d e ', 03 04 05 ,' + * 3 ', 01 02 ,' c f ', 01 02 ,' + * 2 ', 00 ,' b g ', 00 ,' + * 1 '--' a h '--' + * Diagonals are "numbered" 0 to 14 (15 in total); in each diagram the diag + * on the bottom will be #0, the major diagonal will be #7, and the top #14. + * See precomputed.h for values and macros relating to this implementation. + ****************************************************************************/ +typedef struct { + /* These arrays contain basic information about where the pieces are + * on the board. Used generally for masking with attack bitboards. */ + bitboard_t pos[2][6]; /* Positions of each PIECE of COLOR */ + bitboard_t piecesofcolor[2]; /* All squares occupied by COLOR */ + bitboard_t attackedby[2]; /* All squares attacked by COLOR */ + /* Maintain the occupancy status of every square on the board in four + * rotated boards, for easy generation of sliding attacks. */ + bitboard_t occupied; + bitboard_t occupied90; + bitboard_t occupied45; + bitboard_t occupied315; + /* The zobrist hash key for the current position */ + zobrist_t hash; + /* Stores nonrecomputable state for undo. Index into with ->moves. */ + history_t history[HISTORY_STACK_SIZE]; + /* Various flags relating to the current position. Note for the ep + * flag that the capture square will always be on the 3rd (2-index) + * row, or the 6th (5-index) row. A value of zero means no enpassant + * is possible in this position. */ + square_t ep; /* The square on which an ep capture + * could occur */ + unsigned char castle[2][2]; /* Can {WHITE,BLACK} castle {KINGSIDE, + * QUEENSIDE} */ + unsigned char hascastled[2]; /* has {WHITE,BLACK} castled yet */ + unsigned char tomove; /* Who has the move (WHITE, BLACK) */ + unsigned char halfmoves; /* The halfmove clock. A draw occurs when + * this hits 100. */ + unsigned int moves; /* The game move clock. This also counts + * halfmoves, but is never reset. */ + unsigned char reps; /* how many times has this position + * appeared before? if 2, draw */ + int16_t material[2]; /* keeps track of material; see eval.c */ +} board_t; + +/**************************************************************************** + * Some special macros and precomputed bitboards + ****************************************************************************/ +#define BB(b) ((bitboard_t)(b ## ull)) +#define BB_FILEA BB(0x0101010101010101) +#define BB_FILEB BB(0x0202020202020202) +#define BB_FILEC BB(0x0404040404040404) +#define BB_FILED BB(0x0808080808080808) +#define BB_FILEE BB(0x1010101010101010) +#define BB_FILEF BB(0x2020202020202020) +#define BB_FILEG BB(0x4040404040404040) +#define BB_FILEH BB(0x8080808080808080) +#define BB_FILE(c) (BB_FILEA << (c)) +#define BB_RANK1 BB(0x00000000000000ff) +#define BB_RANK2 BB(0x000000000000ff00) +#define BB_RANK3 BB(0x0000000000ff0000) +#define BB_RANK4 BB(0x00000000ff000000) +#define BB_RANK5 BB(0x000000ff00000000) +#define BB_RANK6 BB(0x0000ff0000000000) +#define BB_RANK7 BB(0x00ff000000000000) +#define BB_RANK8 BB(0xff00000000000000) +#define BB_RANK(r) (BB_RANK1 << (8 * (r))) +#define BB_HALF_RANKS(s) (((s) == WHITE) ? BB(0x00000000ffffffff) : BB(0xffffffff00000000)) +#define BB_HALF_FILES(s) (((s) == QUEENSIDE) ? BB(0x0f0f0f0f0f0f0f0f) : BB(0xf0f0f0f0f0f0f0f0)) + + +/* pawnstructure needs these */ +extern bitboard_t bb_adjacentcols[8]; +extern bitboard_t bb_passedpawnmask[2][64]; + +/* BB_SQUARE: Get a bitboard with only one bit set, on a specified square + * Bb_ALLEXCEPT: The bitwise negation of BB_SQUARE(x) */ +//#define BB_SHIFTFLIP /* prefer shift/flip to cached memory lookups */ +#ifdef BB_SHIFTFLIP + #define BB_SQUARE(x) BB((BB(0x1))<<(x)) + #define BB_ALLEXCEPT(x) BB(~(BB_SQUARE(x))) +#else + #define BB_SQUARE(x) bb_square[x] + #define BB_ALLEXCEPT(x) bb_allexcept[x] + extern bitboard_t bb_square[64]; + extern bitboard_t bb_allexcept[64]; +#endif + +/* If you are {white,black}, you ep-capture with a pawn on rank {5,4} */ +#define BB_EP_FROMRANK(c) (((c) == WHITE) ? BB_RANK5 : BB_RANK4) +/* If you are {white,black}, your pawn will be ep-captured on {3,6} */ +#define BB_EP_TORANK(c) (((c) == WHITE) ? BB_RANK3 : BB_RANK6) + +/**************************************************************************** + * Function declarations + ****************************************************************************/ +void init_zobrist(); +void zobrist_gen(board_t *); + +board_t *board_init(); +void board_destroy(board_t *); +char *board_fen(board_t *); +piece_t board_pieceatsquare(board_t *, square_t, unsigned char *); +int board_incheck(board_t *); +int board_colorincheck(board_t *, unsigned char); +int board_mated(board_t *); +int board_pawnpassed(board_t *, square_t, unsigned char); +int board_squareisattacked(board_t *, square_t, unsigned char); +int board_squaresareattacked(board_t *, bitboard_t, unsigned char); +bitboard_t board_attacksfrom(board_t *, square_t, piece_t, unsigned char); +bitboard_t board_pawnpushesfrom(board_t *, square_t, unsigned char); +void board_generatemoves(board_t *, movelist_t *); +void board_generatecaptures(board_t *, movelist_t *); +void board_applymove(board_t *, move_t); +void board_undomove(board_t *, move_t); +bitboard_t board_pawnattacks(bitboard_t pawns, unsigned char); +int board_threefold_draw(board_t *); + +move_t move_fromstring(char *); +move_t move_islegal(board_t *, char *, char **); +char *move_tostring(move_t); + +#endif +/**************************************************************************** + * eval.h - evaluation function to tell how good a position is + * copyright (C) 2008 Ben Blum + ****************************************************************************/ +#ifndef EVAL_H +#define EVAL_H + +#ifndef EVAL_LAZY_THRESHHOLD +#define EVAL_LAZY_THRESHHOLD 250 +#endif + +/** + * Is this board an endgame position + */ +int eval_isendgame(board_t *); + +/** + * Evaluation function. Given a board, returns an int value representing how + * good this position is for whoever has the move. A positive score means the + * player to move has the advantage; a negative score means the player to move + * has the disadvantage; a zero score means both sides have equal chances. + */ +int16_t eval(board_t *); + +/** + * Lazy eval - just the material difference + */ +int16_t eval_lazy(board_t *); + +#endif +/**************************************************************************** + * pawnstructure.h - evaluation helpers to judge pawn structure quality + * copyright (C) 2008 Ben Blum + * ****************************************************************************/ +#ifndef PAWNSTRUCTURE_H +#define PAWNSTRUCTURE_H + +/** + * Evaluate the pawn structure given the position bitboard for the pawns. We + * don't want to consider anything besides the position of the pawns relative + * to each other - this just assigns rewards and penalties for pawn-related + * issues such as doubled pawns, isolated pawns, etcetera. + * Pass in the pawn position bitboard and the color to whom these pwans belong + */ +int16_t eval_pawnstructure(board_t *, unsigned char, bitboard_t *); + +#endif +/**************************************************************************** + * quiescent.h - captures-only search to avoid evaluating unstable position + * copyright (C) 2008 Ben Blum + ****************************************************************************/ +#ifndef QUIESCENT_H +#define QUIESCENT_H + +int16_t quiesce(board_t *board, int16_t alpha, int16_t beta); + +#endif +/**************************************************************************** + * transposition.h - avoid re-searching already searched positions + * copyright (C) 2008 Ben Blum + ****************************************************************************/ +#ifndef TRANSPOSITION_H +#define TRANSPOSITION_H + +/** + * Transposition table - keyed by zobrist hash, stores info about a node. We + * keep track of the following data: + * 1) The best move at this position (possibly 0, if a fail-low occurred) + * 2) The evaluated (or approximate) value of the position + * 3) The depth this node was searched to, or -1 if this was {check,stale}mate + * Note we use -1 (as an unsigned depth value) so that we will always use + * transposition information for terminal nodes rather than wasting time + * figuring out how big the movelist is. + * 4) How far into the game (not search tree) this position is. This data lets + * us always evict nodes beyond which the state of the game has gone. Note, + * 5) What type of values these are: + * Exact value + * Beta cutoff - failed high (storedval is lower bound) + * Alpha cutoff - failed low (storedval is upper bound) + * + * Note: The "depth" should not be simply the depth to which this node was + * searched. It should be instead that depth plus how far into the game we are + * (i.e., the game clock). This will help us replace nodes that are behind our + * search tree entirely - otherwise, the table will fill with high-depth nodes + * that we'll never use because they were back in the beginning of the game. + * When comparing for replacement, use the gamedepth of the root node (the + * position currently on the board), but when adding, use the gamedepth of + * the current node (the position a few moves in the future). Because of + * this the searcher needs to pass both values to trans_add(). + * Definitions: "search depth" refers to how deep this node will be searched; + * "game depth" refer's to THIS NODE's depth in the whole game tree; "root + * depth" refers to how deep the position the searcher started at is. + */ +typedef struct trans_data_t { + /* gcc -O3 optimizes all this into a register; + * note, the element ordering is critical */ + uint8_t flags; + uint8_t gamedepth; + int16_t value; + uint32_t move; +} trans_data_t; +/* The 'flags' field stores the alpha/beta/exact flags in two bits and the + * searched-depth of the node + * BBBBBB AA + * 2 0 + * A: Alpha/beta/exact + * B: searchdepth + * If we search deeper than 63 plies then we're in trouble. + * */ +#define TRANS_FLAG_EXACT 0x2 +#define TRANS_FLAG_BETA 0x1 +#define TRANS_FLAG_ALPHA 0x0 +/* Conversion macros - see trans_data() in trans.c for the other direction */ +#define TRANS_INDEX_FLAG 0 +#define TRANS_INDEX_SEARCHDEPTH 2 +#define TRANS_FLAG(t) (((t).flags >> TRANS_INDEX_FLAG) & 0x3) +#define TRANS_SEARCHDEPTH(t) (((t).flags >> TRANS_INDEX_SEARCHDEPTH) & 0x3f) +#define TRANS_GAMEDEPTH(t) ((t).gamedepth) +#define TRANS_VALUE(t) ((t).value) +#define TRANS_MOVE(t) ((t).move & ((1 << MOV_INDEX_UNUSED) - 1)) +#define TRANS_REPS(t) ((t).move >> MOV_INDEX_UNUSED) + +/* Add an entry. On collision, will succeed only if it's better information */ +void trans_add(zobrist_t, move_t, uint8_t, int16_t, uint8_t, uint8_t, uint8_t, + unsigned char); +/* Find a value from the table. Returns -1 if none exists - you can trust this + * value because a trans_data_t will never be -1 due to the blank bits */ +trans_data_t trans_get(zobrist_t); +/* Check if the return value from get() was valid */ +int trans_data_valid(trans_data_t); + +#endif +/**************************************************************************** + * book.h - simple interface for retrieving moves from a plaintext book + * copyright (C) 2008 Ben Blum + * ****************************************************************************/ +#ifndef BOOK_H +#define BOOK_H + +#define BOOK_LINE_MAX_LENGTH 256 + +move_t book_move(char *line, board_t *board); + +#endif +/**************************************************************************** + * search.h - traverse the game tree looking for the best position + * copyright (C) 2008 Ben Blum + ****************************************************************************/ +#ifndef SEARCH_H +#define SEARCH_H + +/** + * A search function will require the following arguments: + * 1) Board state + * 2) How many seconds we should think before moving + * 3) int * - if nonnull, lets you know how many nodes were searched + * 4) int * - if nonnull, lets you know the alpha value of the position + */ +typedef move_t (*search_fn)(board_t *, unsigned int, int *, int16_t *); + +move_t getbestmove(board_t *, unsigned int, int *, int16_t *); + +#endif +/**************************************************************************** + * engine.c - wrapper functions for managing computer vs human play + * copyright (C) 2008 Ben Blum + ****************************************************************************/ +#ifndef ENGINE_H +#define ENGINE_H + + +#define ENGINE_NAME "bistromath" + +typedef struct engine_t { + board_t *board; + search_fn search; + char line[BOOK_LINE_MAX_LENGTH]; + unsigned int line_moves; + unsigned char inbook; +} engine_t; + +engine_t *engine_init(search_fn); +char *engine_generatemove(engine_t *); +int engine_applymove(engine_t *, char *, char **); +void engine_destroy(engine_t *); + +#endif +/**************************************************************************** + * attacks.c - precomputed attack-/move-mask tables + * copyright (C) 2008 Ben Blum + ****************************************************************************/ + +/* Bitmasks for attackable squares given a square a certain piece is on. Use + * the predefined constants (A1 to H8, 0-63) from bitboard.h, or some other + * way of getting the square in the same format, to index into these arrays */ +uint64_t knightattacks[64] = { + /* A1 to H1 */ + U64(0x0000000000020400), U64(0x0000000000050800), U64(0x00000000000a1100), U64(0x0000000000142200), + U64(0x0000000000284400), U64(0x0000000000508800), U64(0x0000000000a01000), U64(0x0000000000402000), + /* A2 to H2 */ + U64(0x0000000002040004), U64(0x0000000005080008), U64(0x000000000a110011), U64(0x0000000014220022), + U64(0x0000000028440044), U64(0x0000000050880088), U64(0x00000000a0100010), U64(0x0000000040200020), + /* A3 to H3 */ + U64(0x0000000204000402), U64(0x0000000508000805), U64(0x0000000a1100110a), U64(0x0000001422002214), + U64(0x0000002844004428), U64(0x0000005088008850), U64(0x000000a0100010a0), U64(0x0000004020002040), + /* A4 to H4 */ + U64(0x0000020400040200), U64(0x0000050800080500), U64(0x00000a1100110a00), U64(0x0000142200221400), + U64(0x0000284400442800), U64(0x0000508800885000), U64(0x0000a0100010a000), U64(0x0000402000204000), + /* A5 to H5 */ + U64(0x0002040004020000), U64(0x0005080008050000), U64(0x000a1100110a0000), U64(0x0014220022140000), + U64(0x0028440044280000), U64(0x0050880088500000), U64(0x00a0100010a00000), U64(0x0040200020400000), + /* A6 to H6 */ + U64(0x0204000402000000), U64(0x0508000805000000), U64(0x0a1100110a000000), U64(0x1422002214000000), + U64(0x2844004428000000), U64(0x5088008850000000), U64(0xa0100010a0000000), U64(0x4020002040000000), + /* A7 to H7 */ + U64(0x0400040200000000), U64(0x0800080500000000), U64(0x1100110a00000000), U64(0x2200221400000000), + U64(0x4400442800000000), U64(0x8800885000000000), U64(0x100010a000000000), U64(0x2000204000000000), + /* A8 to H8 */ + U64(0x0004020000000000), U64(0x0008050000000000), U64(0x00110a0000000000), U64(0x0022140000000000), + U64(0x0044280000000000), U64(0x0088500000000000), U64(0x0010a00000000000), U64(0x0020400000000000) +}; +uint64_t kingattacks[64] = { + /* A1 to H1 */ + U64(0x0000000000000302), U64(0x0000000000000705), U64(0x0000000000000e0a), U64(0x0000000000001c14), + U64(0x0000000000003828), U64(0x0000000000007050), U64(0x000000000000e0a0), U64(0x000000000000c040), + /* A2 to H2 */ + U64(0x0000000000030203), U64(0x0000000000070507), U64(0x00000000000e0a0e), U64(0x00000000001c141c), + U64(0x0000000000382838), U64(0x0000000000705070), U64(0x0000000000e0a0e0), U64(0x0000000000c040c0), + /* A3 to H3 */ + U64(0x0000000003020300), U64(0x0000000007050700), U64(0x000000000e0a0e00), U64(0x000000001c141c00), + U64(0x0000000038283800), U64(0x0000000070507000), U64(0x00000000e0a0e000), U64(0x00000000c040c000), + /* A4 to H4 */ + U64(0x0000000302030000), U64(0x0000000705070000), U64(0x0000000e0a0e0000), U64(0x0000001c141c0000), + U64(0x0000003828380000), U64(0x0000007050700000), U64(0x000000e0a0e00000), U64(0x000000c040c00000), + /* A5 to H5 */ + U64(0x0000030203000000), U64(0x0000070507000000), U64(0x00000e0a0e000000), U64(0x00001c141c000000), + U64(0x0000382838000000), U64(0x0000705070000000), U64(0x0000e0a0e0000000), U64(0x0000c040c0000000), + /* A6 to H6 */ + U64(0x0003020300000000), U64(0x0007050700000000), U64(0x000e0a0e00000000), U64(0x001c141c00000000), + U64(0x0038283800000000), U64(0x0070507000000000), U64(0x00e0a0e000000000), U64(0x00c040c000000000), + /* A7 to H7 */ + U64(0x0302030000000000), U64(0x0705070000000000), U64(0x0e0a0e0000000000), U64(0x1c141c0000000000), + U64(0x3828380000000000), U64(0x7050700000000000), U64(0xe0a0e00000000000), U64(0xc040c00000000000), + /* A8 to H8 */ + U64(0x0203000000000000), U64(0x0507000000000000), U64(0x0a0e000000000000), U64(0x141c000000000000), + U64(0x2838000000000000), U64(0x5070000000000000), U64(0xa0e0000000000000), U64(0x40c0000000000000) +}; +uint64_t pawnattacks[2][64] = { + { /* WHITE */ + /* A1 to H1 */ + U64(0x0000000000000200), U64(0x0000000000000500), U64(0x0000000000000a00), U64(0x0000000000001400), + U64(0x0000000000002800), U64(0x0000000000005000), U64(0x000000000000a000), U64(0x0000000000004000), + /* A2 to H2 */ + U64(0x0000000000020000), U64(0x0000000000050000), U64(0x00000000000a0000), U64(0x0000000000140000), + U64(0x0000000000280000), U64(0x0000000000500000), U64(0x0000000000a00000), U64(0x0000000000400000), + /* A3 to H3 */ + U64(0x0000000002000000), U64(0x0000000005000000), U64(0x000000000a000000), U64(0x0000000014000000), + U64(0x0000000028000000), U64(0x0000000050000000), U64(0x00000000a0000000), U64(0x0000000040000000), + /* A4 to H4 */ + U64(0x0000000200000000), U64(0x0000000500000000), U64(0x0000000a00000000), U64(0x0000001400000000), + U64(0x0000002800000000), U64(0x0000005000000000), U64(0x000000a000000000), U64(0x0000004000000000), + /* A5 to H5 */ + U64(0x0000020000000000), U64(0x0000050000000000), U64(0x00000a0000000000), U64(0x0000140000000000), + U64(0x0000280000000000), U64(0x0000500000000000), U64(0x0000a00000000000), U64(0x0000400000000000), + /* A6 to H6 */ + U64(0x0002000000000000), U64(0x0005000000000000), U64(0x000a000000000000), U64(0x0014000000000000), + U64(0x0028000000000000), U64(0x0050000000000000), U64(0x00a0000000000000), U64(0x0040000000000000), + /* A7 to H7 */ + U64(0x0200000000000000), U64(0x0500000000000000), U64(0x0a00000000000000), U64(0x1400000000000000), + U64(0x2800000000000000), U64(0x5000000000000000), U64(0xa000000000000000), U64(0x4000000000000000), + /* A8 to H8 */ + U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), + U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000) + }, + { /* BLACK */ + /* A1 to H1 */ + U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), + U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), + /* A2 to H2 */ + U64(0x0000000000000002), U64(0x0000000000000005), U64(0x000000000000000a), U64(0x0000000000000014), + U64(0x0000000000000028), U64(0x0000000000000050), U64(0x00000000000000a0), U64(0x0000000000000040), + /* A3 to H3 */ + U64(0x0000000000000200), U64(0x0000000000000500), U64(0x0000000000000a00), U64(0x0000000000001400), + U64(0x0000000000002800), U64(0x0000000000005000), U64(0x000000000000a000), U64(0x0000000000004000), + /* A4 to H4 */ + U64(0x0000000000020000), U64(0x0000000000050000), U64(0x00000000000a0000), U64(0x0000000000140000), + U64(0x0000000000280000), U64(0x0000000000500000), U64(0x0000000000a00000), U64(0x0000000000400000), + /* A5 to H5 */ + U64(0x0000000002000000), U64(0x0000000005000000), U64(0x000000000a000000), U64(0x0000000014000000), + U64(0x0000000028000000), U64(0x0000000050000000), U64(0x00000000a0000000), U64(0x0000000040000000), + /* A6 to H6 */ + U64(0x0000000200000000), U64(0x0000000500000000), U64(0x0000000a00000000), U64(0x0000001400000000), + U64(0x0000002800000000), U64(0x0000005000000000), U64(0x000000a000000000), U64(0x0000004000000000), + /* A7 to H7 */ + U64(0x0000020000000000), U64(0x0000050000000000), U64(0x00000a0000000000), U64(0x0000140000000000), + U64(0x0000280000000000), U64(0x0000500000000000), U64(0x0000a00000000000), U64(0x0000400000000000), + /* A8 to H8 */ + U64(0x0002000000000000), U64(0x0005000000000000), U64(0x000a000000000000), U64(0x0014000000000000), + U64(0x0028000000000000), U64(0x0050000000000000), U64(0x00a0000000000000), U64(0x0040000000000000) + } +}; +/* Don't account for the double-pawn-pushes; the pawn moves generator takes + * care of that */ +uint64_t pawnmoves[2][64] = { + { /* WHITE */ + /* A1 to H1 */ + U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), + U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), + /* A2 to H2 */ + U64(0x0000000000010000), U64(0x0000000000020000), U64(0x0000000000040000), U64(0x0000000000080000), + U64(0x0000000000100000), U64(0x0000000000200000), U64(0x0000000000400000), U64(0x0000000000800000), + /* A3 to H3 */ + U64(0x0000000001000000), U64(0x0000000002000000), U64(0x0000000004000000), U64(0x0000000008000000), + U64(0x0000000010000000), U64(0x0000000020000000), U64(0x0000000040000000), U64(0x0000000080000000), + /* A4 to H4 */ + U64(0x0000000100000000), U64(0x0000000200000000), U64(0x0000000400000000), U64(0x0000000800000000), + U64(0x0000001000000000), U64(0x0000002000000000), U64(0x0000004000000000), U64(0x0000008000000000), + /* A5 to H5 */ + U64(0x0000010000000000), U64(0x0000020000000000), U64(0x0000040000000000), U64(0x0000080000000000), + U64(0x0000100000000000), U64(0x0000200000000000), U64(0x0000400000000000), U64(0x0000800000000000), + /* A6 to H6 */ + U64(0x0001000000000000), U64(0x0002000000000000), U64(0x0004000000000000), U64(0x0008000000000000), + U64(0x0010000000000000), U64(0x0020000000000000), U64(0x0040000000000000), U64(0x0080000000000000), + /* A7 to H7 */ + U64(0x0100000000000000), U64(0x0200000000000000), U64(0x0400000000000000), U64(0x0800000000000000), + U64(0x1000000000000000), U64(0x2000000000000000), U64(0x4000000000000000), U64(0x8000000000000000), + /* A8 to H8 */ + U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), + U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000) + }, + { /* BLACK */ + /* A1 to H1 */ + U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), + U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), + /* A2 to H2 */ + U64(0x0000000000000001), U64(0x0000000000000002), U64(0x0000000000000004), U64(0x0000000000000008), + U64(0x0000000000000010), U64(0x0000000000000020), U64(0x0000000000000040), U64(0x0000000000000080), + /* A3 to H3 */ + U64(0x0000000000000100), U64(0x0000000000000200), U64(0x0000000000000400), U64(0x0000000000000800), + U64(0x0000000000001000), U64(0x0000000000002000), U64(0x0000000000004000), U64(0x0000000000008000), + /* A4 to H4 */ + U64(0x0000000000010000), U64(0x0000000000020000), U64(0x0000000000040000), U64(0x0000000000080000), + U64(0x0000000000100000), U64(0x0000000000200000), U64(0x0000000000400000), U64(0x0000000000800000), + /* A5 to H5 */ + U64(0x0000000001000000), U64(0x0000000002000000), U64(0x0000000004000000), U64(0x0000000008000000), + U64(0x0000000010000000), U64(0x0000000020000000), U64(0x0000000040000000), U64(0x0000000080000000), + /* A6 to H6 */ + U64(0x0000000100000000), U64(0x0000000200000000), U64(0x0000000400000000), U64(0x0000000800000000), + U64(0x0000001000000000), U64(0x0000002000000000), U64(0x0000004000000000), U64(0x0000008000000000), + /* A7 to H7 */ + U64(0x0000010000000000), U64(0x0000020000000000), U64(0x0000040000000000), U64(0x0000080000000000), + U64(0x0000100000000000), U64(0x0000200000000000), U64(0x0000400000000000), U64(0x0000800000000000), + /* A8 to H8 */ + U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), + U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000) + } +}; + +/** + * For rook attacks along a row. Uses the 'occupied' status of the row (e.g. + * if there are pieces on the columns a, d, e, f, h , the bitmask will be + * (binary) 00111001) as the first index, and the position of the rook (0-7 + * for columns 1-8 (right to left on the mask)) as the second index. + * + * It returns a row mask appropriate for a rook on the 1st (0 index) row's + * attacks; note that the bit at the end of the attack ray will overlap the + * first blocking piece (a rook on d-column with rowblock mask 11010011 (note + * the 1 in the d-col indicates the rook itself) will get move mask 01101110 + * (note again the 0 on the d-column; the rook cannot move to itself)). + * + * Because the return is suitable for a rook on row-1 (0 index), it must be + * shifted left by 8*ROW(square) - for example, on the 8th row, the shift by + * 8*7 will put it in the MSBs of the uint64_t. + */ +uint64_t rowattacks[256][8] = { + { U64(0xfe), U64(0xfd), U64(0xfb), U64(0xf7), U64(0xef), U64(0xdf), U64(0xbf), U64(0x7f) }, /* 0x00 */ + { U64(0xfe), U64(0xfd), U64(0xfb), U64(0xf7), U64(0xef), U64(0xdf), U64(0xbf), U64(0x7f) }, /* 0x01 */ + { U64(0x02), U64(0xfd), U64(0xfa), U64(0xf6), U64(0xee), U64(0xde), U64(0xbe), U64(0x7e) }, /* 0x02 */ + { U64(0x02), U64(0xfd), U64(0xfa), U64(0xf6), U64(0xee), U64(0xde), U64(0xbe), U64(0x7e) }, /* 0x03 */ + { U64(0x06), U64(0x05), U64(0xfb), U64(0xf4), U64(0xec), U64(0xdc), U64(0xbc), U64(0x7c) }, /* 0x04 */ + { U64(0x06), U64(0x05), U64(0xfb), U64(0xf4), U64(0xec), U64(0xdc), U64(0xbc), U64(0x7c) }, /* 0x05 */ + { U64(0x02), U64(0x05), U64(0xfa), U64(0xf4), U64(0xec), U64(0xdc), U64(0xbc), U64(0x7c) }, /* 0x06 */ + { U64(0x02), U64(0x05), U64(0xfa), U64(0xf4), U64(0xec), U64(0xdc), U64(0xbc), U64(0x7c) }, /* 0x07 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0xf7), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x08 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0xf7), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x09 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0xf6), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x0a */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0xf6), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x0b */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0xf4), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x0c */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0xf4), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x0d */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0xf4), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x0e */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0xf4), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x0f */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0xef), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x10 */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0xef), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x11 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0xee), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x12 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0xee), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x13 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0xec), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x14 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0xec), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x15 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0xec), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x16 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0xec), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x17 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x18 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x19 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x1a */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x1b */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x1c */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x1d */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x1e */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x1f */ + { U64(0x3e), U64(0x3d), U64(0x3b), U64(0x37), U64(0x2f), U64(0xdf), U64(0xa0), U64(0x60) }, /* 0x20 */ + { U64(0x3e), U64(0x3d), U64(0x3b), U64(0x37), U64(0x2f), U64(0xdf), U64(0xa0), U64(0x60) }, /* 0x21 */ + { U64(0x02), U64(0x3d), U64(0x3a), U64(0x36), U64(0x2e), U64(0xde), U64(0xa0), U64(0x60) }, /* 0x22 */ + { U64(0x02), U64(0x3d), U64(0x3a), U64(0x36), U64(0x2e), U64(0xde), U64(0xa0), U64(0x60) }, /* 0x23 */ + { U64(0x06), U64(0x05), U64(0x3b), U64(0x34), U64(0x2c), U64(0xdc), U64(0xa0), U64(0x60) }, /* 0x24 */ + { U64(0x06), U64(0x05), U64(0x3b), U64(0x34), U64(0x2c), U64(0xdc), U64(0xa0), U64(0x60) }, /* 0x25 */ + { U64(0x02), U64(0x05), U64(0x3a), U64(0x34), U64(0x2c), U64(0xdc), U64(0xa0), U64(0x60) }, /* 0x26 */ + { U64(0x02), U64(0x05), U64(0x3a), U64(0x34), U64(0x2c), U64(0xdc), U64(0xa0), U64(0x60) }, /* 0x27 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x37), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0x28 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x37), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0x29 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x36), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0x2a */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x36), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0x2b */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x34), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0x2c */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x34), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0x2d */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x34), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0x2e */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x34), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0x2f */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0x2f), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x30 */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0x2f), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x31 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0x2e), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x32 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0x2e), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x33 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0x2c), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x34 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0x2c), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x35 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0x2c), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x36 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0x2c), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x37 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x38 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x39 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x3a */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x3b */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x3c */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x3d */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x3e */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x3f */ + { U64(0x7e), U64(0x7d), U64(0x7b), U64(0x77), U64(0x6f), U64(0x5f), U64(0xbf), U64(0x40) }, /* 0x40 */ + { U64(0x7e), U64(0x7d), U64(0x7b), U64(0x77), U64(0x6f), U64(0x5f), U64(0xbf), U64(0x40) }, /* 0x41 */ + { U64(0x02), U64(0x7d), U64(0x7a), U64(0x76), U64(0x6e), U64(0x5e), U64(0xbe), U64(0x40) }, /* 0x42 */ + { U64(0x02), U64(0x7d), U64(0x7a), U64(0x76), U64(0x6e), U64(0x5e), U64(0xbe), U64(0x40) }, /* 0x43 */ + { U64(0x06), U64(0x05), U64(0x7b), U64(0x74), U64(0x6c), U64(0x5c), U64(0xbc), U64(0x40) }, /* 0x44 */ + { U64(0x06), U64(0x05), U64(0x7b), U64(0x74), U64(0x6c), U64(0x5c), U64(0xbc), U64(0x40) }, /* 0x45 */ + { U64(0x02), U64(0x05), U64(0x7a), U64(0x74), U64(0x6c), U64(0x5c), U64(0xbc), U64(0x40) }, /* 0x46 */ + { U64(0x02), U64(0x05), U64(0x7a), U64(0x74), U64(0x6c), U64(0x5c), U64(0xbc), U64(0x40) }, /* 0x47 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x77), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0x48 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x77), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0x49 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x76), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0x4a */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x76), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0x4b */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x74), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0x4c */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x74), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0x4d */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x74), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0x4e */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x74), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0x4f */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0x6f), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x50 */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0x6f), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x51 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0x6e), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x52 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0x6e), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x53 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0x6c), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x54 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0x6c), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x55 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0x6c), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x56 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0x6c), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x57 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x58 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x59 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x5a */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x5b */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x5c */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x5d */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x5e */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x5f */ + { U64(0x3e), U64(0x3d), U64(0x3b), U64(0x37), U64(0x2f), U64(0x5f), U64(0xa0), U64(0x40) }, /* 0x60 */ + { U64(0x3e), U64(0x3d), U64(0x3b), U64(0x37), U64(0x2f), U64(0x5f), U64(0xa0), U64(0x40) }, /* 0x61 */ + { U64(0x02), U64(0x3d), U64(0x3a), U64(0x36), U64(0x2e), U64(0x5e), U64(0xa0), U64(0x40) }, /* 0x62 */ + { U64(0x02), U64(0x3d), U64(0x3a), U64(0x36), U64(0x2e), U64(0x5e), U64(0xa0), U64(0x40) }, /* 0x63 */ + { U64(0x06), U64(0x05), U64(0x3b), U64(0x34), U64(0x2c), U64(0x5c), U64(0xa0), U64(0x40) }, /* 0x64 */ + { U64(0x06), U64(0x05), U64(0x3b), U64(0x34), U64(0x2c), U64(0x5c), U64(0xa0), U64(0x40) }, /* 0x65 */ + { U64(0x02), U64(0x05), U64(0x3a), U64(0x34), U64(0x2c), U64(0x5c), U64(0xa0), U64(0x40) }, /* 0x66 */ + { U64(0x02), U64(0x05), U64(0x3a), U64(0x34), U64(0x2c), U64(0x5c), U64(0xa0), U64(0x40) }, /* 0x67 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x37), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0x68 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x37), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0x69 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x36), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0x6a */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x36), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0x6b */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x34), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0x6c */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x34), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0x6d */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x34), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0x6e */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x34), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0x6f */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0x2f), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x70 */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0x2f), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x71 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0x2e), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x72 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0x2e), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x73 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0x2c), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x74 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0x2c), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x75 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0x2c), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x76 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0x2c), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x77 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x78 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x79 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x7a */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x7b */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x7c */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x7d */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x7e */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x7f */ + { U64(0xfe), U64(0xfd), U64(0xfb), U64(0xf7), U64(0xef), U64(0xdf), U64(0xbf), U64(0x7f) }, /* 0x80 */ + { U64(0xfe), U64(0xfd), U64(0xfb), U64(0xf7), U64(0xef), U64(0xdf), U64(0xbf), U64(0x7f) }, /* 0x81 */ + { U64(0x02), U64(0xfd), U64(0xfa), U64(0xf6), U64(0xee), U64(0xde), U64(0xbe), U64(0x7e) }, /* 0x82 */ + { U64(0x02), U64(0xfd), U64(0xfa), U64(0xf6), U64(0xee), U64(0xde), U64(0xbe), U64(0x7e) }, /* 0x83 */ + { U64(0x06), U64(0x05), U64(0xfb), U64(0xf4), U64(0xec), U64(0xdc), U64(0xbc), U64(0x7c) }, /* 0x84 */ + { U64(0x06), U64(0x05), U64(0xfb), U64(0xf4), U64(0xec), U64(0xdc), U64(0xbc), U64(0x7c) }, /* 0x85 */ + { U64(0x02), U64(0x05), U64(0xfa), U64(0xf4), U64(0xec), U64(0xdc), U64(0xbc), U64(0x7c) }, /* 0x86 */ + { U64(0x02), U64(0x05), U64(0xfa), U64(0xf4), U64(0xec), U64(0xdc), U64(0xbc), U64(0x7c) }, /* 0x87 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0xf7), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x88 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0xf7), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x89 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0xf6), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x8a */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0xf6), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x8b */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0xf4), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x8c */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0xf4), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x8d */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0xf4), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x8e */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0xf4), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x8f */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0xef), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x90 */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0xef), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x91 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0xee), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x92 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0xee), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x93 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0xec), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x94 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0xec), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x95 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0xec), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x96 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0xec), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x97 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x98 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x99 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x9a */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x9b */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x9c */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x9d */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x9e */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x9f */ + { U64(0x3e), U64(0x3d), U64(0x3b), U64(0x37), U64(0x2f), U64(0xdf), U64(0xa0), U64(0x60) }, /* 0xa0 */ + { U64(0x3e), U64(0x3d), U64(0x3b), U64(0x37), U64(0x2f), U64(0xdf), U64(0xa0), U64(0x60) }, /* 0xa1 */ + { U64(0x02), U64(0x3d), U64(0x3a), U64(0x36), U64(0x2e), U64(0xde), U64(0xa0), U64(0x60) }, /* 0xa2 */ + { U64(0x02), U64(0x3d), U64(0x3a), U64(0x36), U64(0x2e), U64(0xde), U64(0xa0), U64(0x60) }, /* 0xa3 */ + { U64(0x06), U64(0x05), U64(0x3b), U64(0x34), U64(0x2c), U64(0xdc), U64(0xa0), U64(0x60) }, /* 0xa4 */ + { U64(0x06), U64(0x05), U64(0x3b), U64(0x34), U64(0x2c), U64(0xdc), U64(0xa0), U64(0x60) }, /* 0xa5 */ + { U64(0x02), U64(0x05), U64(0x3a), U64(0x34), U64(0x2c), U64(0xdc), U64(0xa0), U64(0x60) }, /* 0xa6 */ + { U64(0x02), U64(0x05), U64(0x3a), U64(0x34), U64(0x2c), U64(0xdc), U64(0xa0), U64(0x60) }, /* 0xa7 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x37), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0xa8 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x37), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0xa9 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x36), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0xaa */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x36), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0xab */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x34), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0xac */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x34), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0xad */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x34), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0xae */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x34), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0xaf */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0x2f), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xb0 */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0x2f), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xb1 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0x2e), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xb2 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0x2e), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xb3 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0x2c), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xb4 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0x2c), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xb5 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0x2c), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xb6 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0x2c), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xb7 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xb8 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xb9 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xba */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xbb */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xbc */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xbd */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xbe */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xbf */ + { U64(0x7e), U64(0x7d), U64(0x7b), U64(0x77), U64(0x6f), U64(0x5f), U64(0xbf), U64(0x40) }, /* 0xc0 */ + { U64(0x7e), U64(0x7d), U64(0x7b), U64(0x77), U64(0x6f), U64(0x5f), U64(0xbf), U64(0x40) }, /* 0xc1 */ + { U64(0x02), U64(0x7d), U64(0x7a), U64(0x76), U64(0x6e), U64(0x5e), U64(0xbe), U64(0x40) }, /* 0xc2 */ + { U64(0x02), U64(0x7d), U64(0x7a), U64(0x76), U64(0x6e), U64(0x5e), U64(0xbe), U64(0x40) }, /* 0xc3 */ + { U64(0x06), U64(0x05), U64(0x7b), U64(0x74), U64(0x6c), U64(0x5c), U64(0xbc), U64(0x40) }, /* 0xc4 */ + { U64(0x06), U64(0x05), U64(0x7b), U64(0x74), U64(0x6c), U64(0x5c), U64(0xbc), U64(0x40) }, /* 0xc5 */ + { U64(0x02), U64(0x05), U64(0x7a), U64(0x74), U64(0x6c), U64(0x5c), U64(0xbc), U64(0x40) }, /* 0xc6 */ + { U64(0x02), U64(0x05), U64(0x7a), U64(0x74), U64(0x6c), U64(0x5c), U64(0xbc), U64(0x40) }, /* 0xc7 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x77), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0xc8 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x77), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0xc9 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x76), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0xca */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x76), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0xcb */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x74), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0xcc */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x74), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0xcd */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x74), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0xce */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x74), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0xcf */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0x6f), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xd0 */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0x6f), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xd1 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0x6e), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xd2 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0x6e), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xd3 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0x6c), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xd4 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0x6c), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xd5 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0x6c), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xd6 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0x6c), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xd7 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xd8 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xd9 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xda */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xdb */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xdc */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xdd */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xde */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xdf */ + { U64(0x3e), U64(0x3d), U64(0x3b), U64(0x37), U64(0x2f), U64(0x5f), U64(0xa0), U64(0x40) }, /* 0xe0 */ + { U64(0x3e), U64(0x3d), U64(0x3b), U64(0x37), U64(0x2f), U64(0x5f), U64(0xa0), U64(0x40) }, /* 0xe1 */ + { U64(0x02), U64(0x3d), U64(0x3a), U64(0x36), U64(0x2e), U64(0x5e), U64(0xa0), U64(0x40) }, /* 0xe2 */ + { U64(0x02), U64(0x3d), U64(0x3a), U64(0x36), U64(0x2e), U64(0x5e), U64(0xa0), U64(0x40) }, /* 0xe3 */ + { U64(0x06), U64(0x05), U64(0x3b), U64(0x34), U64(0x2c), U64(0x5c), U64(0xa0), U64(0x40) }, /* 0xe4 */ + { U64(0x06), U64(0x05), U64(0x3b), U64(0x34), U64(0x2c), U64(0x5c), U64(0xa0), U64(0x40) }, /* 0xe5 */ + { U64(0x02), U64(0x05), U64(0x3a), U64(0x34), U64(0x2c), U64(0x5c), U64(0xa0), U64(0x40) }, /* 0xe6 */ + { U64(0x02), U64(0x05), U64(0x3a), U64(0x34), U64(0x2c), U64(0x5c), U64(0xa0), U64(0x40) }, /* 0xe7 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x37), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0xe8 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x37), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0xe9 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x36), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0xea */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x36), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0xeb */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x34), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0xec */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x34), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0xed */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x34), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0xee */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x34), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0xef */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0x2f), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xf0 */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0x2f), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xf1 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0x2e), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xf2 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0x2e), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xf3 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0x2c), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xf4 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0x2c), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xf5 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0x2c), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xf6 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0x2c), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xf7 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xf8 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xf9 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xfa */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xfb */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xfc */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xfd */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xfe */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) } /* 0xff */ +}; + + +/**************************************************************************** + * For rook attacks along a column. Using the 'occupied' status of the column + * passed in from the rot90 bitboard, shifted to the 8 least-significant bits + * (a-column), returns a NON-ROTATED bitmask of attacks for the a-column. You + * will want to shift this result over by COL(square) bits to get it in the + * right place - think about the way the bitboard works; each row is a byte + * (major index, times 8), and each column is a bit (minor index, times 1). + * You will want to use whatever ROW the piece is on in a normal bitboard as + * the second index. + ****************************************************************************/ + +uint64_t colattacks[256][8] = { + { U64(0x0101010101010100), U64(0x0101010101010001), U64(0x0101010101000101), U64(0x0101010100010101), U64(0x0101010001010101), U64(0x0101000101010101), U64(0x0100010101010101), U64(0x0001010101010101) }, /* 0x00 */ + { U64(0x0101010101010100), U64(0x0101010101010001), U64(0x0101010101000101), U64(0x0101010100010101), U64(0x0101010001010101), U64(0x0101000101010101), U64(0x0100010101010101), U64(0x0001010101010101) }, /* 0x01 */ + { U64(0x0000000000000100), U64(0x0101010101010001), U64(0x0101010101000100), U64(0x0101010100010100), U64(0x0101010001010100), U64(0x0101000101010100), U64(0x0100010101010100), U64(0x0001010101010100) }, /* 0x02 */ + { U64(0x0000000000000100), U64(0x0101010101010001), U64(0x0101010101000100), U64(0x0101010100010100), U64(0x0101010001010100), U64(0x0101000101010100), U64(0x0100010101010100), U64(0x0001010101010100) }, /* 0x03 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0101010101000101), U64(0x0101010100010000), U64(0x0101010001010000), U64(0x0101000101010000), U64(0x0100010101010000), U64(0x0001010101010000) }, /* 0x04 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0101010101000101), U64(0x0101010100010000), U64(0x0101010001010000), U64(0x0101000101010000), U64(0x0100010101010000), U64(0x0001010101010000) }, /* 0x05 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0101010101000100), U64(0x0101010100010000), U64(0x0101010001010000), U64(0x0101000101010000), U64(0x0100010101010000), U64(0x0001010101010000) }, /* 0x06 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0101010101000100), U64(0x0101010100010000), U64(0x0101010001010000), U64(0x0101000101010000), U64(0x0100010101010000), U64(0x0001010101010000) }, /* 0x07 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0101010100010101), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x08 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0101010100010101), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x09 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0101010100010100), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x0a */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0101010100010100), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x0b */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0101010100010000), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x0c */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0101010100010000), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x0d */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0101010100010000), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x0e */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0101010100010000), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x0f */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0101010001010101), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x10 */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0101010001010101), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x11 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0101010001010100), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x12 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0101010001010100), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x13 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0101010001010000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x14 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0101010001010000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x15 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0101010001010000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x16 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0101010001010000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x17 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x18 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x19 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x1a */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x1b */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x1c */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x1d */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x1e */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x1f */ + { U64(0x0000010101010100), U64(0x0000010101010001), U64(0x0000010101000101), U64(0x0000010100010101), U64(0x0000010001010101), U64(0x0101000101010101), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x20 */ + { U64(0x0000010101010100), U64(0x0000010101010001), U64(0x0000010101000101), U64(0x0000010100010101), U64(0x0000010001010101), U64(0x0101000101010101), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x21 */ + { U64(0x0000000000000100), U64(0x0000010101010001), U64(0x0000010101000100), U64(0x0000010100010100), U64(0x0000010001010100), U64(0x0101000101010100), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x22 */ + { U64(0x0000000000000100), U64(0x0000010101010001), U64(0x0000010101000100), U64(0x0000010100010100), U64(0x0000010001010100), U64(0x0101000101010100), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x23 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000010101000101), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0101000101010000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x24 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000010101000101), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0101000101010000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x25 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000010101000100), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0101000101010000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x26 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000010101000100), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0101000101010000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x27 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000010100010101), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x28 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000010100010101), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x29 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000010100010100), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x2a */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000010100010100), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x2b */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x2c */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x2d */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x2e */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x2f */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0000010001010101), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x30 */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0000010001010101), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x31 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0000010001010100), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x32 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0000010001010100), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x33 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x34 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x35 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x36 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x37 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x38 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x39 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x3a */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x3b */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x3c */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x3d */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x3e */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x3f */ + { U64(0x0001010101010100), U64(0x0001010101010001), U64(0x0001010101000101), U64(0x0001010100010101), U64(0x0001010001010101), U64(0x0001000101010101), U64(0x0100010101010101), U64(0x0001000000000000) }, /* 0x40 */ + { U64(0x0001010101010100), U64(0x0001010101010001), U64(0x0001010101000101), U64(0x0001010100010101), U64(0x0001010001010101), U64(0x0001000101010101), U64(0x0100010101010101), U64(0x0001000000000000) }, /* 0x41 */ + { U64(0x0000000000000100), U64(0x0001010101010001), U64(0x0001010101000100), U64(0x0001010100010100), U64(0x0001010001010100), U64(0x0001000101010100), U64(0x0100010101010100), U64(0x0001000000000000) }, /* 0x42 */ + { U64(0x0000000000000100), U64(0x0001010101010001), U64(0x0001010101000100), U64(0x0001010100010100), U64(0x0001010001010100), U64(0x0001000101010100), U64(0x0100010101010100), U64(0x0001000000000000) }, /* 0x43 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0001010101000101), U64(0x0001010100010000), U64(0x0001010001010000), U64(0x0001000101010000), U64(0x0100010101010000), U64(0x0001000000000000) }, /* 0x44 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0001010101000101), U64(0x0001010100010000), U64(0x0001010001010000), U64(0x0001000101010000), U64(0x0100010101010000), U64(0x0001000000000000) }, /* 0x45 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0001010101000100), U64(0x0001010100010000), U64(0x0001010001010000), U64(0x0001000101010000), U64(0x0100010101010000), U64(0x0001000000000000) }, /* 0x46 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0001010101000100), U64(0x0001010100010000), U64(0x0001010001010000), U64(0x0001000101010000), U64(0x0100010101010000), U64(0x0001000000000000) }, /* 0x47 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0001010100010101), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0x48 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0001010100010101), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0x49 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0001010100010100), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0x4a */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0001010100010100), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0x4b */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0001010100010000), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0x4c */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0001010100010000), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0x4d */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0001010100010000), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0x4e */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0001010100010000), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0x4f */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0001010001010101), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x50 */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0001010001010101), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x51 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0001010001010100), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x52 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0001010001010100), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x53 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0001010001010000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x54 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0001010001010000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x55 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0001010001010000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x56 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0001010001010000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x57 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x58 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x59 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x5a */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x5b */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x5c */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x5d */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x5e */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x5f */ + { U64(0x0000010101010100), U64(0x0000010101010001), U64(0x0000010101000101), U64(0x0000010100010101), U64(0x0000010001010101), U64(0x0001000101010101), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x60 */ + { U64(0x0000010101010100), U64(0x0000010101010001), U64(0x0000010101000101), U64(0x0000010100010101), U64(0x0000010001010101), U64(0x0001000101010101), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x61 */ + { U64(0x0000000000000100), U64(0x0000010101010001), U64(0x0000010101000100), U64(0x0000010100010100), U64(0x0000010001010100), U64(0x0001000101010100), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x62 */ + { U64(0x0000000000000100), U64(0x0000010101010001), U64(0x0000010101000100), U64(0x0000010100010100), U64(0x0000010001010100), U64(0x0001000101010100), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x63 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000010101000101), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0001000101010000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x64 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000010101000101), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0001000101010000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x65 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000010101000100), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0001000101010000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x66 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000010101000100), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0001000101010000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x67 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000010100010101), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x68 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000010100010101), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x69 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000010100010100), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x6a */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000010100010100), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x6b */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x6c */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x6d */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x6e */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x6f */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0000010001010101), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x70 */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0000010001010101), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x71 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0000010001010100), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x72 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0000010001010100), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x73 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x74 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x75 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x76 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x77 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x78 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x79 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x7a */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x7b */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x7c */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x7d */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x7e */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x7f */ + { U64(0x0101010101010100), U64(0x0101010101010001), U64(0x0101010101000101), U64(0x0101010100010101), U64(0x0101010001010101), U64(0x0101000101010101), U64(0x0100010101010101), U64(0x0001010101010101) }, /* 0x80 */ + { U64(0x0101010101010100), U64(0x0101010101010001), U64(0x0101010101000101), U64(0x0101010100010101), U64(0x0101010001010101), U64(0x0101000101010101), U64(0x0100010101010101), U64(0x0001010101010101) }, /* 0x81 */ + { U64(0x0000000000000100), U64(0x0101010101010001), U64(0x0101010101000100), U64(0x0101010100010100), U64(0x0101010001010100), U64(0x0101000101010100), U64(0x0100010101010100), U64(0x0001010101010100) }, /* 0x82 */ + { U64(0x0000000000000100), U64(0x0101010101010001), U64(0x0101010101000100), U64(0x0101010100010100), U64(0x0101010001010100), U64(0x0101000101010100), U64(0x0100010101010100), U64(0x0001010101010100) }, /* 0x83 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0101010101000101), U64(0x0101010100010000), U64(0x0101010001010000), U64(0x0101000101010000), U64(0x0100010101010000), U64(0x0001010101010000) }, /* 0x84 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0101010101000101), U64(0x0101010100010000), U64(0x0101010001010000), U64(0x0101000101010000), U64(0x0100010101010000), U64(0x0001010101010000) }, /* 0x85 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0101010101000100), U64(0x0101010100010000), U64(0x0101010001010000), U64(0x0101000101010000), U64(0x0100010101010000), U64(0x0001010101010000) }, /* 0x86 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0101010101000100), U64(0x0101010100010000), U64(0x0101010001010000), U64(0x0101000101010000), U64(0x0100010101010000), U64(0x0001010101010000) }, /* 0x87 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0101010100010101), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x88 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0101010100010101), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x89 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0101010100010100), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x8a */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0101010100010100), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x8b */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0101010100010000), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x8c */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0101010100010000), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x8d */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0101010100010000), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x8e */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0101010100010000), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x8f */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0101010001010101), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x90 */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0101010001010101), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x91 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0101010001010100), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x92 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0101010001010100), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x93 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0101010001010000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x94 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0101010001010000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x95 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0101010001010000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x96 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0101010001010000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x97 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x98 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x99 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x9a */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x9b */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x9c */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x9d */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x9e */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x9f */ + { U64(0x0000010101010100), U64(0x0000010101010001), U64(0x0000010101000101), U64(0x0000010100010101), U64(0x0000010001010101), U64(0x0101000101010101), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xa0 */ + { U64(0x0000010101010100), U64(0x0000010101010001), U64(0x0000010101000101), U64(0x0000010100010101), U64(0x0000010001010101), U64(0x0101000101010101), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xa1 */ + { U64(0x0000000000000100), U64(0x0000010101010001), U64(0x0000010101000100), U64(0x0000010100010100), U64(0x0000010001010100), U64(0x0101000101010100), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xa2 */ + { U64(0x0000000000000100), U64(0x0000010101010001), U64(0x0000010101000100), U64(0x0000010100010100), U64(0x0000010001010100), U64(0x0101000101010100), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xa3 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000010101000101), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0101000101010000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xa4 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000010101000101), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0101000101010000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xa5 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000010101000100), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0101000101010000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xa6 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000010101000100), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0101000101010000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xa7 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000010100010101), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xa8 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000010100010101), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xa9 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000010100010100), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xaa */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000010100010100), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xab */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xac */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xad */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xae */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xaf */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0000010001010101), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xb0 */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0000010001010101), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xb1 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0000010001010100), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xb2 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0000010001010100), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xb3 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xb4 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xb5 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xb6 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xb7 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xb8 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xb9 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xba */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xbb */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xbc */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xbd */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xbe */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xbf */ + { U64(0x0001010101010100), U64(0x0001010101010001), U64(0x0001010101000101), U64(0x0001010100010101), U64(0x0001010001010101), U64(0x0001000101010101), U64(0x0100010101010101), U64(0x0001000000000000) }, /* 0xc0 */ + { U64(0x0001010101010100), U64(0x0001010101010001), U64(0x0001010101000101), U64(0x0001010100010101), U64(0x0001010001010101), U64(0x0001000101010101), U64(0x0100010101010101), U64(0x0001000000000000) }, /* 0xc1 */ + { U64(0x0000000000000100), U64(0x0001010101010001), U64(0x0001010101000100), U64(0x0001010100010100), U64(0x0001010001010100), U64(0x0001000101010100), U64(0x0100010101010100), U64(0x0001000000000000) }, /* 0xc2 */ + { U64(0x0000000000000100), U64(0x0001010101010001), U64(0x0001010101000100), U64(0x0001010100010100), U64(0x0001010001010100), U64(0x0001000101010100), U64(0x0100010101010100), U64(0x0001000000000000) }, /* 0xc3 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0001010101000101), U64(0x0001010100010000), U64(0x0001010001010000), U64(0x0001000101010000), U64(0x0100010101010000), U64(0x0001000000000000) }, /* 0xc4 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0001010101000101), U64(0x0001010100010000), U64(0x0001010001010000), U64(0x0001000101010000), U64(0x0100010101010000), U64(0x0001000000000000) }, /* 0xc5 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0001010101000100), U64(0x0001010100010000), U64(0x0001010001010000), U64(0x0001000101010000), U64(0x0100010101010000), U64(0x0001000000000000) }, /* 0xc6 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0001010101000100), U64(0x0001010100010000), U64(0x0001010001010000), U64(0x0001000101010000), U64(0x0100010101010000), U64(0x0001000000000000) }, /* 0xc7 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0001010100010101), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0xc8 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0001010100010101), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0xc9 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0001010100010100), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0xca */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0001010100010100), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0xcb */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0001010100010000), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0xcc */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0001010100010000), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0xcd */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0001010100010000), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0xce */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0001010100010000), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0xcf */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0001010001010101), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xd0 */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0001010001010101), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xd1 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0001010001010100), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xd2 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0001010001010100), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xd3 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0001010001010000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xd4 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0001010001010000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xd5 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0001010001010000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xd6 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0001010001010000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xd7 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xd8 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xd9 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xda */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xdb */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xdc */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xdd */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xde */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xdf */ + { U64(0x0000010101010100), U64(0x0000010101010001), U64(0x0000010101000101), U64(0x0000010100010101), U64(0x0000010001010101), U64(0x0001000101010101), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xe0 */ + { U64(0x0000010101010100), U64(0x0000010101010001), U64(0x0000010101000101), U64(0x0000010100010101), U64(0x0000010001010101), U64(0x0001000101010101), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xe1 */ + { U64(0x0000000000000100), U64(0x0000010101010001), U64(0x0000010101000100), U64(0x0000010100010100), U64(0x0000010001010100), U64(0x0001000101010100), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xe2 */ + { U64(0x0000000000000100), U64(0x0000010101010001), U64(0x0000010101000100), U64(0x0000010100010100), U64(0x0000010001010100), U64(0x0001000101010100), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xe3 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000010101000101), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0001000101010000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xe4 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000010101000101), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0001000101010000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xe5 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000010101000100), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0001000101010000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xe6 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000010101000100), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0001000101010000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xe7 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000010100010101), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xe8 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000010100010101), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xe9 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000010100010100), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xea */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000010100010100), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xeb */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xec */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xed */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xee */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xef */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0000010001010101), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xf0 */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0000010001010101), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xf1 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0000010001010100), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xf2 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0000010001010100), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xf3 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xf4 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xf5 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xf6 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xf7 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xf8 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xf9 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xfa */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xfb */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xfc */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xfd */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xfe */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) } /* 0xff */ +}; + +/**************************************************************************** + * For bishop attacks along a diagonal parallel to a8-h1 (rot45). This is + * kind of special, because each diagonal is a different length you need to + * think carefully about how the shifting works. This will give the move mask + * for a bishop on the a8-h1 diagonal (the longest one) in NON-ROTATED format. + * + * Think carefully about how you want to shift. When you get the result back, + * you will want to shift it forward or backward exactly 8 times N, where N is + * the number of diagonals the one your bishop is on is away from a8-h1 (a + * bishop on a8-h1 will be shifted 0. For a bishop on a7-g1 you will shift + * RIGHT by 8 bits; a6-f1 RIGHT by 16 bits, a1-a1 RIGHT by 56 bits. On the + * other hand, for a bishop on b8-h2 you will shift LEFT 8 bits, c8-h3 LEFT by + * 16 bits, h8-h8 LEFT by 56 bits. + * + * The other important thing to consider is how you go into the table. Because + * the diagonals are not all the same length, you need to aligh one edge of + * your diagonal to either the 0 index OR the other edge to the 7 index. The + * way you want to do it is if your diagonal touches the left side of the + * board (aX-x1), shift so the square on the a-file is in the 0th index; if + * your diagonal touches the right side (x8-hX), shift so the square on the + * h-file will be in the 7th index. Either way, this means there will be some + * garbage not related to your diagonal in the remaining slots - it will + * affect the resulting move mask, but when you bitshift it (according to the + * previous paragraph) the nonrelevant squares in the mask will overflow out. + * + * To get a piece's position on the diagonal (the second index in the array), + * we consider alignment described above, and realize that because essentially + * we're projecting the diagonal down to the first (0-index) row, plus some + * garbage, the position index is simply the column the piece is on! + ****************************************************************************/ + +/* Use these to get the number used to index into the next few arrays. Indexed + * by square (A1 0, H8 63) for both rotation directions. Use the result from + * these arrays as an index into the "shiftamount" arrays following. */ +int rot45diagindex[64] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 1, 2, 3, 4, 5, 6, 7, 8, + 2, 3, 4, 5, 6, 7, 8, 9, + 3, 4, 5, 6, 7, 8, 9, 10, + 4, 5, 6, 7, 8, 9, 10, 11, + 5, 6, 7, 8, 9, 10, 11, 12, + 6, 7, 8, 9, 10, 11, 12, 13, + 7, 8, 9, 10, 11, 12, 13, 14 +}; +int rot315diagindex[64] = { + 7, 6, 5, 4, 3, 2, 1, 0, + 8, 7, 6, 5, 4, 3, 2, 1, + 9, 8, 7, 6, 5, 4, 3, 2, + 10, 9, 8, 7, 6, 5, 4, 3, + 11, 10, 9, 8, 7, 6, 5, 4, + 12, 11, 10, 9, 8, 7, 6, 5, + 13, 12, 11, 10, 9, 8, 7, 6, + 14, 13, 12, 11, 10, 9, 8, 7 +}; + +/* The amount you want to shift the rotated bitboard by (then mask with 0xFF) + * to get the correct index. Index into this with the diagonal's number. For + * rot45, you want to align >7 diagonals against the 7th index, with garbage + * in the bottom, or <7 diagonals against the 0th index, with garbage in the + * top, so that when shifting the garbage goes out of the top/bottom of the + * board. For rot315 it's the opposite case - >7 diags get aligned to the 0th + * index, and <7 diags aligned to the 7th index; this way, the garbage will + * still go out the top/bottom of the board. For the lowest diagonals, this + * means we might have to shift backwards. (note: The numbers for aligning to + * the top bits are generated by "extending" the row backwards.) */ +int rot45index_shiftamountright[15] = { 0, 1, 3, 6, 10, 15, 21, 28, 35, 41, 46, 50, 53, 55, 56 }; +int rot315index_shiftamountright[15] = { 0, 0, 0, 2, 7, 13, 20, 28, 36, 43, 49, 54, 58, 61, 63 }; +int rot315index_shiftamountleft[15] = { 7, 5, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +/* The amount you want to shift the result by. Use the number of the diagonal + * (0 for a1-a1, 7 for a8-h1, 14 for h8-h8) to index into these. */ +int rotresult_shiftamountleft[15] = { 0, 0, 0, 0, 0, 0, 0, 0, 8, 16, 24, 32, 40, 48, 56 }; +int rotresult_shiftamountright[15] = { 56, 48, 40, 32, 24, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0 }; + +uint64_t rot45attacks[256][8] = { + { U64(0x0002040810204080), U64(0x0100040810204080), U64(0x0102000810204080), U64(0x0102040010204080), U64(0x0102040800204080), U64(0x0102040810004080), U64(0x0102040810200080), U64(0x0102040810204000) }, /* 0x00 */ + { U64(0x0002040810204080), U64(0x0100040810204080), U64(0x0102000810204080), U64(0x0102040010204080), U64(0x0102040800204080), U64(0x0102040810004080), U64(0x0102040810200080), U64(0x0102040810204000) }, /* 0x01 */ + { U64(0x0002000000000000), U64(0x0100040810204080), U64(0x0002000810204080), U64(0x0002040010204080), U64(0x0002040800204080), U64(0x0002040810004080), U64(0x0002040810200080), U64(0x0002040810204000) }, /* 0x02 */ + { U64(0x0002000000000000), U64(0x0100040810204080), U64(0x0002000810204080), U64(0x0002040010204080), U64(0x0002040800204080), U64(0x0002040810004080), U64(0x0002040810200080), U64(0x0002040810204000) }, /* 0x03 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810204080), U64(0x0000040010204080), U64(0x0000040800204080), U64(0x0000040810004080), U64(0x0000040810200080), U64(0x0000040810204000) }, /* 0x04 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810204080), U64(0x0000040010204080), U64(0x0000040800204080), U64(0x0000040810004080), U64(0x0000040810200080), U64(0x0000040810204000) }, /* 0x05 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810204080), U64(0x0000040010204080), U64(0x0000040800204080), U64(0x0000040810004080), U64(0x0000040810200080), U64(0x0000040810204000) }, /* 0x06 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810204080), U64(0x0000040010204080), U64(0x0000040800204080), U64(0x0000040810004080), U64(0x0000040810200080), U64(0x0000040810204000) }, /* 0x07 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x08 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x09 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x0a */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x0b */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x0c */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x0d */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x0e */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x0f */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x10 */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x11 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x12 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x13 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x14 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x15 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x16 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x17 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x18 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x19 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x1a */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x1b */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x1c */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x1d */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x1e */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x1f */ + { U64(0x0002040810200000), U64(0x0100040810200000), U64(0x0102000810200000), U64(0x0102040010200000), U64(0x0102040800200000), U64(0x0102040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x20 */ + { U64(0x0002040810200000), U64(0x0100040810200000), U64(0x0102000810200000), U64(0x0102040010200000), U64(0x0102040800200000), U64(0x0102040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x21 */ + { U64(0x0002000000000000), U64(0x0100040810200000), U64(0x0002000810200000), U64(0x0002040010200000), U64(0x0002040800200000), U64(0x0002040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x22 */ + { U64(0x0002000000000000), U64(0x0100040810200000), U64(0x0002000810200000), U64(0x0002040010200000), U64(0x0002040800200000), U64(0x0002040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x23 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x24 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x25 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x26 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x27 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x28 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x29 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x2a */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x2b */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x2c */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x2d */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x2e */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x2f */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x30 */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x31 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x32 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x33 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x34 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x35 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x36 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x37 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x38 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x39 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x3a */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x3b */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x3c */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x3d */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x3e */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x3f */ + { U64(0x0002040810204000), U64(0x0100040810204000), U64(0x0102000810204000), U64(0x0102040010204000), U64(0x0102040800204000), U64(0x0102040810004000), U64(0x0102040810200080), U64(0x0000000000004000) }, /* 0x40 */ + { U64(0x0002040810204000), U64(0x0100040810204000), U64(0x0102000810204000), U64(0x0102040010204000), U64(0x0102040800204000), U64(0x0102040810004000), U64(0x0102040810200080), U64(0x0000000000004000) }, /* 0x41 */ + { U64(0x0002000000000000), U64(0x0100040810204000), U64(0x0002000810204000), U64(0x0002040010204000), U64(0x0002040800204000), U64(0x0002040810004000), U64(0x0002040810200080), U64(0x0000000000004000) }, /* 0x42 */ + { U64(0x0002000000000000), U64(0x0100040810204000), U64(0x0002000810204000), U64(0x0002040010204000), U64(0x0002040800204000), U64(0x0002040810004000), U64(0x0002040810200080), U64(0x0000000000004000) }, /* 0x43 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810204000), U64(0x0000040010204000), U64(0x0000040800204000), U64(0x0000040810004000), U64(0x0000040810200080), U64(0x0000000000004000) }, /* 0x44 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810204000), U64(0x0000040010204000), U64(0x0000040800204000), U64(0x0000040810004000), U64(0x0000040810200080), U64(0x0000000000004000) }, /* 0x45 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810204000), U64(0x0000040010204000), U64(0x0000040800204000), U64(0x0000040810004000), U64(0x0000040810200080), U64(0x0000000000004000) }, /* 0x46 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810204000), U64(0x0000040010204000), U64(0x0000040800204000), U64(0x0000040810004000), U64(0x0000040810200080), U64(0x0000000000004000) }, /* 0x47 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0x48 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0x49 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0x4a */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0x4b */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0x4c */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0x4d */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0x4e */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0x4f */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x50 */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x51 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x52 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x53 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x54 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x55 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x56 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x57 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x58 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x59 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x5a */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x5b */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x5c */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x5d */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x5e */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x5f */ + { U64(0x0002040810200000), U64(0x0100040810200000), U64(0x0102000810200000), U64(0x0102040010200000), U64(0x0102040800200000), U64(0x0102040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x60 */ + { U64(0x0002040810200000), U64(0x0100040810200000), U64(0x0102000810200000), U64(0x0102040010200000), U64(0x0102040800200000), U64(0x0102040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x61 */ + { U64(0x0002000000000000), U64(0x0100040810200000), U64(0x0002000810200000), U64(0x0002040010200000), U64(0x0002040800200000), U64(0x0002040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x62 */ + { U64(0x0002000000000000), U64(0x0100040810200000), U64(0x0002000810200000), U64(0x0002040010200000), U64(0x0002040800200000), U64(0x0002040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x63 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x64 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x65 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x66 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x67 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x68 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x69 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x6a */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x6b */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x6c */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x6d */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x6e */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x6f */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x70 */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x71 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x72 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x73 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x74 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x75 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x76 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x77 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x78 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x79 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x7a */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x7b */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x7c */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x7d */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x7e */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x7f */ + { U64(0x0002040810204080), U64(0x0100040810204080), U64(0x0102000810204080), U64(0x0102040010204080), U64(0x0102040800204080), U64(0x0102040810004080), U64(0x0102040810200080), U64(0x0102040810204000) }, /* 0x80 */ + { U64(0x0002040810204080), U64(0x0100040810204080), U64(0x0102000810204080), U64(0x0102040010204080), U64(0x0102040800204080), U64(0x0102040810004080), U64(0x0102040810200080), U64(0x0102040810204000) }, /* 0x81 */ + { U64(0x0002000000000000), U64(0x0100040810204080), U64(0x0002000810204080), U64(0x0002040010204080), U64(0x0002040800204080), U64(0x0002040810004080), U64(0x0002040810200080), U64(0x0002040810204000) }, /* 0x82 */ + { U64(0x0002000000000000), U64(0x0100040810204080), U64(0x0002000810204080), U64(0x0002040010204080), U64(0x0002040800204080), U64(0x0002040810004080), U64(0x0002040810200080), U64(0x0002040810204000) }, /* 0x83 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810204080), U64(0x0000040010204080), U64(0x0000040800204080), U64(0x0000040810004080), U64(0x0000040810200080), U64(0x0000040810204000) }, /* 0x84 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810204080), U64(0x0000040010204080), U64(0x0000040800204080), U64(0x0000040810004080), U64(0x0000040810200080), U64(0x0000040810204000) }, /* 0x85 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810204080), U64(0x0000040010204080), U64(0x0000040800204080), U64(0x0000040810004080), U64(0x0000040810200080), U64(0x0000040810204000) }, /* 0x86 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810204080), U64(0x0000040010204080), U64(0x0000040800204080), U64(0x0000040810004080), U64(0x0000040810200080), U64(0x0000040810204000) }, /* 0x87 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x88 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x89 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x8a */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x8b */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x8c */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x8d */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x8e */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x8f */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x90 */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x91 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x92 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x93 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x94 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x95 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x96 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x97 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x98 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x99 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x9a */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x9b */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x9c */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x9d */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x9e */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x9f */ + { U64(0x0002040810200000), U64(0x0100040810200000), U64(0x0102000810200000), U64(0x0102040010200000), U64(0x0102040800200000), U64(0x0102040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xa0 */ + { U64(0x0002040810200000), U64(0x0100040810200000), U64(0x0102000810200000), U64(0x0102040010200000), U64(0x0102040800200000), U64(0x0102040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xa1 */ + { U64(0x0002000000000000), U64(0x0100040810200000), U64(0x0002000810200000), U64(0x0002040010200000), U64(0x0002040800200000), U64(0x0002040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xa2 */ + { U64(0x0002000000000000), U64(0x0100040810200000), U64(0x0002000810200000), U64(0x0002040010200000), U64(0x0002040800200000), U64(0x0002040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xa3 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xa4 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xa5 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xa6 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xa7 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xa8 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xa9 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xaa */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xab */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xac */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xad */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xae */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xaf */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xb0 */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xb1 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xb2 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xb3 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xb4 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xb5 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xb6 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xb7 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xb8 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xb9 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xba */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xbb */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xbc */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xbd */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xbe */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xbf */ + { U64(0x0002040810204000), U64(0x0100040810204000), U64(0x0102000810204000), U64(0x0102040010204000), U64(0x0102040800204000), U64(0x0102040810004000), U64(0x0102040810200080), U64(0x0000000000004000) }, /* 0xc0 */ + { U64(0x0002040810204000), U64(0x0100040810204000), U64(0x0102000810204000), U64(0x0102040010204000), U64(0x0102040800204000), U64(0x0102040810004000), U64(0x0102040810200080), U64(0x0000000000004000) }, /* 0xc1 */ + { U64(0x0002000000000000), U64(0x0100040810204000), U64(0x0002000810204000), U64(0x0002040010204000), U64(0x0002040800204000), U64(0x0002040810004000), U64(0x0002040810200080), U64(0x0000000000004000) }, /* 0xc2 */ + { U64(0x0002000000000000), U64(0x0100040810204000), U64(0x0002000810204000), U64(0x0002040010204000), U64(0x0002040800204000), U64(0x0002040810004000), U64(0x0002040810200080), U64(0x0000000000004000) }, /* 0xc3 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810204000), U64(0x0000040010204000), U64(0x0000040800204000), U64(0x0000040810004000), U64(0x0000040810200080), U64(0x0000000000004000) }, /* 0xc4 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810204000), U64(0x0000040010204000), U64(0x0000040800204000), U64(0x0000040810004000), U64(0x0000040810200080), U64(0x0000000000004000) }, /* 0xc5 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810204000), U64(0x0000040010204000), U64(0x0000040800204000), U64(0x0000040810004000), U64(0x0000040810200080), U64(0x0000000000004000) }, /* 0xc6 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810204000), U64(0x0000040010204000), U64(0x0000040800204000), U64(0x0000040810004000), U64(0x0000040810200080), U64(0x0000000000004000) }, /* 0xc7 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0xc8 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0xc9 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0xca */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0xcb */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0xcc */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0xcd */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0xce */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0xcf */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xd0 */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xd1 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xd2 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xd3 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xd4 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xd5 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xd6 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xd7 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xd8 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xd9 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xda */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xdb */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xdc */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xdd */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xde */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xdf */ + { U64(0x0002040810200000), U64(0x0100040810200000), U64(0x0102000810200000), U64(0x0102040010200000), U64(0x0102040800200000), U64(0x0102040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xe0 */ + { U64(0x0002040810200000), U64(0x0100040810200000), U64(0x0102000810200000), U64(0x0102040010200000), U64(0x0102040800200000), U64(0x0102040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xe1 */ + { U64(0x0002000000000000), U64(0x0100040810200000), U64(0x0002000810200000), U64(0x0002040010200000), U64(0x0002040800200000), U64(0x0002040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xe2 */ + { U64(0x0002000000000000), U64(0x0100040810200000), U64(0x0002000810200000), U64(0x0002040010200000), U64(0x0002040800200000), U64(0x0002040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xe3 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xe4 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xe5 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xe6 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xe7 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xe8 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xe9 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xea */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xeb */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xec */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xed */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xee */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xef */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xf0 */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xf1 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xf2 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xf3 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xf4 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xf5 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xf6 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xf7 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xf8 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xf9 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xfa */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xfb */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xfc */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xfd */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xfe */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) } /* 0xff */ +}; + +uint64_t rot315attacks[256][8] = { + { U64(0x8040201008040200), U64(0x8040201008040001), U64(0x8040201008000201), U64(0x8040201000040201), U64(0x8040200008040201), U64(0x8040001008040201), U64(0x8000201008040201), U64(0x0040201008040201) }, /* 0x00 */ + { U64(0x8040201008040200), U64(0x8040201008040001), U64(0x8040201008000201), U64(0x8040201000040201), U64(0x8040200008040201), U64(0x8040001008040201), U64(0x8000201008040201), U64(0x0040201008040201) }, /* 0x01 */ + { U64(0x0000000000000200), U64(0x8040201008040001), U64(0x8040201008000200), U64(0x8040201000040200), U64(0x8040200008040200), U64(0x8040001008040200), U64(0x8000201008040200), U64(0x0040201008040200) }, /* 0x02 */ + { U64(0x0000000000000200), U64(0x8040201008040001), U64(0x8040201008000200), U64(0x8040201000040200), U64(0x8040200008040200), U64(0x8040001008040200), U64(0x8000201008040200), U64(0x0040201008040200) }, /* 0x03 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x8040201008000201), U64(0x8040201000040000), U64(0x8040200008040000), U64(0x8040001008040000), U64(0x8000201008040000), U64(0x0040201008040000) }, /* 0x04 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x8040201008000201), U64(0x8040201000040000), U64(0x8040200008040000), U64(0x8040001008040000), U64(0x8000201008040000), U64(0x0040201008040000) }, /* 0x05 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x8040201008000200), U64(0x8040201000040000), U64(0x8040200008040000), U64(0x8040001008040000), U64(0x8000201008040000), U64(0x0040201008040000) }, /* 0x06 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x8040201008000200), U64(0x8040201000040000), U64(0x8040200008040000), U64(0x8040001008040000), U64(0x8000201008040000), U64(0x0040201008040000) }, /* 0x07 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x8040201000040201), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x08 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x8040201000040201), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x09 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x8040201000040200), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x0a */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x8040201000040200), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x0b */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x8040201000040000), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x0c */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x8040201000040000), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x0d */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x8040201000040000), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x0e */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x8040201000040000), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x0f */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x8040200008040201), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x10 */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x8040200008040201), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x11 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x8040200008040200), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x12 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x8040200008040200), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x13 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x8040200008040000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x14 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x8040200008040000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x15 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x8040200008040000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x16 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x8040200008040000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x17 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x18 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x19 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x1a */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x1b */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x1c */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x1d */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x1e */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x1f */ + { U64(0x0000201008040200), U64(0x0000201008040001), U64(0x0000201008000201), U64(0x0000201000040201), U64(0x0000200008040201), U64(0x8040001008040201), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x20 */ + { U64(0x0000201008040200), U64(0x0000201008040001), U64(0x0000201008000201), U64(0x0000201000040201), U64(0x0000200008040201), U64(0x8040001008040201), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x21 */ + { U64(0x0000000000000200), U64(0x0000201008040001), U64(0x0000201008000200), U64(0x0000201000040200), U64(0x0000200008040200), U64(0x8040001008040200), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x22 */ + { U64(0x0000000000000200), U64(0x0000201008040001), U64(0x0000201008000200), U64(0x0000201000040200), U64(0x0000200008040200), U64(0x8040001008040200), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x23 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000201008000201), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x8040001008040000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x24 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000201008000201), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x8040001008040000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x25 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000201008000200), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x8040001008040000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x26 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000201008000200), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x8040001008040000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x27 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000201000040201), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x28 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000201000040201), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x29 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000201000040200), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x2a */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000201000040200), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x2b */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x2c */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x2d */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x2e */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x2f */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x0000200008040201), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x30 */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x0000200008040201), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x31 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x0000200008040200), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x32 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x0000200008040200), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x33 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x34 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x35 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x36 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x37 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x38 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x39 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x3a */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x3b */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x3c */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x3d */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x3e */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x3f */ + { U64(0x0040201008040200), U64(0x0040201008040001), U64(0x0040201008000201), U64(0x0040201000040201), U64(0x0040200008040201), U64(0x0040001008040201), U64(0x8000201008040201), U64(0x0040000000000000) }, /* 0x40 */ + { U64(0x0040201008040200), U64(0x0040201008040001), U64(0x0040201008000201), U64(0x0040201000040201), U64(0x0040200008040201), U64(0x0040001008040201), U64(0x8000201008040201), U64(0x0040000000000000) }, /* 0x41 */ + { U64(0x0000000000000200), U64(0x0040201008040001), U64(0x0040201008000200), U64(0x0040201000040200), U64(0x0040200008040200), U64(0x0040001008040200), U64(0x8000201008040200), U64(0x0040000000000000) }, /* 0x42 */ + { U64(0x0000000000000200), U64(0x0040201008040001), U64(0x0040201008000200), U64(0x0040201000040200), U64(0x0040200008040200), U64(0x0040001008040200), U64(0x8000201008040200), U64(0x0040000000000000) }, /* 0x43 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0040201008000201), U64(0x0040201000040000), U64(0x0040200008040000), U64(0x0040001008040000), U64(0x8000201008040000), U64(0x0040000000000000) }, /* 0x44 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0040201008000201), U64(0x0040201000040000), U64(0x0040200008040000), U64(0x0040001008040000), U64(0x8000201008040000), U64(0x0040000000000000) }, /* 0x45 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0040201008000200), U64(0x0040201000040000), U64(0x0040200008040000), U64(0x0040001008040000), U64(0x8000201008040000), U64(0x0040000000000000) }, /* 0x46 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0040201008000200), U64(0x0040201000040000), U64(0x0040200008040000), U64(0x0040001008040000), U64(0x8000201008040000), U64(0x0040000000000000) }, /* 0x47 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0040201000040201), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0x48 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0040201000040201), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0x49 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0040201000040200), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0x4a */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0040201000040200), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0x4b */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0040201000040000), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0x4c */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0040201000040000), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0x4d */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0040201000040000), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0x4e */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0040201000040000), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0x4f */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x0040200008040201), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x50 */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x0040200008040201), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x51 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x0040200008040200), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x52 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x0040200008040200), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x53 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x0040200008040000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x54 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x0040200008040000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x55 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x0040200008040000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x56 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x0040200008040000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x57 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x58 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x59 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x5a */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x5b */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x5c */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x5d */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x5e */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x5f */ + { U64(0x0000201008040200), U64(0x0000201008040001), U64(0x0000201008000201), U64(0x0000201000040201), U64(0x0000200008040201), U64(0x0040001008040201), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x60 */ + { U64(0x0000201008040200), U64(0x0000201008040001), U64(0x0000201008000201), U64(0x0000201000040201), U64(0x0000200008040201), U64(0x0040001008040201), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x61 */ + { U64(0x0000000000000200), U64(0x0000201008040001), U64(0x0000201008000200), U64(0x0000201000040200), U64(0x0000200008040200), U64(0x0040001008040200), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x62 */ + { U64(0x0000000000000200), U64(0x0000201008040001), U64(0x0000201008000200), U64(0x0000201000040200), U64(0x0000200008040200), U64(0x0040001008040200), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x63 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000201008000201), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x0040001008040000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x64 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000201008000201), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x0040001008040000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x65 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000201008000200), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x0040001008040000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x66 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000201008000200), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x0040001008040000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x67 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000201000040201), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x68 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000201000040201), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x69 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000201000040200), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x6a */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000201000040200), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x6b */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x6c */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x6d */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x6e */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x6f */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x0000200008040201), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x70 */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x0000200008040201), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x71 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x0000200008040200), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x72 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x0000200008040200), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x73 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x74 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x75 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x76 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x77 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x78 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x79 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x7a */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x7b */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x7c */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x7d */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x7e */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x7f */ + { U64(0x8040201008040200), U64(0x8040201008040001), U64(0x8040201008000201), U64(0x8040201000040201), U64(0x8040200008040201), U64(0x8040001008040201), U64(0x8000201008040201), U64(0x0040201008040201) }, /* 0x80 */ + { U64(0x8040201008040200), U64(0x8040201008040001), U64(0x8040201008000201), U64(0x8040201000040201), U64(0x8040200008040201), U64(0x8040001008040201), U64(0x8000201008040201), U64(0x0040201008040201) }, /* 0x81 */ + { U64(0x0000000000000200), U64(0x8040201008040001), U64(0x8040201008000200), U64(0x8040201000040200), U64(0x8040200008040200), U64(0x8040001008040200), U64(0x8000201008040200), U64(0x0040201008040200) }, /* 0x82 */ + { U64(0x0000000000000200), U64(0x8040201008040001), U64(0x8040201008000200), U64(0x8040201000040200), U64(0x8040200008040200), U64(0x8040001008040200), U64(0x8000201008040200), U64(0x0040201008040200) }, /* 0x83 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x8040201008000201), U64(0x8040201000040000), U64(0x8040200008040000), U64(0x8040001008040000), U64(0x8000201008040000), U64(0x0040201008040000) }, /* 0x84 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x8040201008000201), U64(0x8040201000040000), U64(0x8040200008040000), U64(0x8040001008040000), U64(0x8000201008040000), U64(0x0040201008040000) }, /* 0x85 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x8040201008000200), U64(0x8040201000040000), U64(0x8040200008040000), U64(0x8040001008040000), U64(0x8000201008040000), U64(0x0040201008040000) }, /* 0x86 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x8040201008000200), U64(0x8040201000040000), U64(0x8040200008040000), U64(0x8040001008040000), U64(0x8000201008040000), U64(0x0040201008040000) }, /* 0x87 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x8040201000040201), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x88 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x8040201000040201), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x89 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x8040201000040200), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x8a */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x8040201000040200), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x8b */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x8040201000040000), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x8c */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x8040201000040000), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x8d */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x8040201000040000), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x8e */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x8040201000040000), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x8f */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x8040200008040201), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x90 */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x8040200008040201), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x91 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x8040200008040200), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x92 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x8040200008040200), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x93 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x8040200008040000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x94 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x8040200008040000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x95 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x8040200008040000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x96 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x8040200008040000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x97 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x98 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x99 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x9a */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x9b */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x9c */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x9d */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x9e */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x9f */ + { U64(0x0000201008040200), U64(0x0000201008040001), U64(0x0000201008000201), U64(0x0000201000040201), U64(0x0000200008040201), U64(0x8040001008040201), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xa0 */ + { U64(0x0000201008040200), U64(0x0000201008040001), U64(0x0000201008000201), U64(0x0000201000040201), U64(0x0000200008040201), U64(0x8040001008040201), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xa1 */ + { U64(0x0000000000000200), U64(0x0000201008040001), U64(0x0000201008000200), U64(0x0000201000040200), U64(0x0000200008040200), U64(0x8040001008040200), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xa2 */ + { U64(0x0000000000000200), U64(0x0000201008040001), U64(0x0000201008000200), U64(0x0000201000040200), U64(0x0000200008040200), U64(0x8040001008040200), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xa3 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000201008000201), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x8040001008040000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xa4 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000201008000201), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x8040001008040000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xa5 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000201008000200), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x8040001008040000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xa6 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000201008000200), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x8040001008040000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xa7 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000201000040201), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xa8 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000201000040201), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xa9 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000201000040200), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xaa */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000201000040200), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xab */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xac */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xad */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xae */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xaf */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x0000200008040201), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xb0 */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x0000200008040201), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xb1 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x0000200008040200), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xb2 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x0000200008040200), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xb3 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xb4 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xb5 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xb6 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xb7 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xb8 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xb9 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xba */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xbb */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xbc */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xbd */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xbe */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xbf */ + { U64(0x0040201008040200), U64(0x0040201008040001), U64(0x0040201008000201), U64(0x0040201000040201), U64(0x0040200008040201), U64(0x0040001008040201), U64(0x8000201008040201), U64(0x0040000000000000) }, /* 0xc0 */ + { U64(0x0040201008040200), U64(0x0040201008040001), U64(0x0040201008000201), U64(0x0040201000040201), U64(0x0040200008040201), U64(0x0040001008040201), U64(0x8000201008040201), U64(0x0040000000000000) }, /* 0xc1 */ + { U64(0x0000000000000200), U64(0x0040201008040001), U64(0x0040201008000200), U64(0x0040201000040200), U64(0x0040200008040200), U64(0x0040001008040200), U64(0x8000201008040200), U64(0x0040000000000000) }, /* 0xc2 */ + { U64(0x0000000000000200), U64(0x0040201008040001), U64(0x0040201008000200), U64(0x0040201000040200), U64(0x0040200008040200), U64(0x0040001008040200), U64(0x8000201008040200), U64(0x0040000000000000) }, /* 0xc3 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0040201008000201), U64(0x0040201000040000), U64(0x0040200008040000), U64(0x0040001008040000), U64(0x8000201008040000), U64(0x0040000000000000) }, /* 0xc4 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0040201008000201), U64(0x0040201000040000), U64(0x0040200008040000), U64(0x0040001008040000), U64(0x8000201008040000), U64(0x0040000000000000) }, /* 0xc5 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0040201008000200), U64(0x0040201000040000), U64(0x0040200008040000), U64(0x0040001008040000), U64(0x8000201008040000), U64(0x0040000000000000) }, /* 0xc6 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0040201008000200), U64(0x0040201000040000), U64(0x0040200008040000), U64(0x0040001008040000), U64(0x8000201008040000), U64(0x0040000000000000) }, /* 0xc7 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0040201000040201), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0xc8 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0040201000040201), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0xc9 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0040201000040200), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0xca */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0040201000040200), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0xcb */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0040201000040000), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0xcc */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0040201000040000), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0xcd */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0040201000040000), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0xce */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0040201000040000), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0xcf */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x0040200008040201), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xd0 */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x0040200008040201), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xd1 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x0040200008040200), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xd2 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x0040200008040200), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xd3 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x0040200008040000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xd4 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x0040200008040000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xd5 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x0040200008040000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xd6 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x0040200008040000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xd7 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xd8 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xd9 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xda */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xdb */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xdc */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xdd */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xde */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xdf */ + { U64(0x0000201008040200), U64(0x0000201008040001), U64(0x0000201008000201), U64(0x0000201000040201), U64(0x0000200008040201), U64(0x0040001008040201), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xe0 */ + { U64(0x0000201008040200), U64(0x0000201008040001), U64(0x0000201008000201), U64(0x0000201000040201), U64(0x0000200008040201), U64(0x0040001008040201), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xe1 */ + { U64(0x0000000000000200), U64(0x0000201008040001), U64(0x0000201008000200), U64(0x0000201000040200), U64(0x0000200008040200), U64(0x0040001008040200), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xe2 */ + { U64(0x0000000000000200), U64(0x0000201008040001), U64(0x0000201008000200), U64(0x0000201000040200), U64(0x0000200008040200), U64(0x0040001008040200), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xe3 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000201008000201), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x0040001008040000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xe4 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000201008000201), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x0040001008040000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xe5 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000201008000200), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x0040001008040000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xe6 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000201008000200), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x0040001008040000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xe7 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000201000040201), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xe8 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000201000040201), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xe9 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000201000040200), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xea */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000201000040200), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xeb */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xec */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xed */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xee */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xef */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x0000200008040201), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xf0 */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x0000200008040201), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xf1 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x0000200008040200), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xf2 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x0000200008040200), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xf3 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xf4 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xf5 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xf6 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xf7 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xf8 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xf9 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xfa */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xfb */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xfc */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xfd */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xfe */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) } /* 0xff */ +}; +/**************************************************************************** + * board.c - rotated bitboard library; move generation and board state + * copyright (C) 2008 Ben Blum + ****************************************************************************/ + +/* For FEN conversion, and move->string conversion */ +char *piecename[2][6] = { + { "P", "N", "B", "R", "Q", "K" }, + { "p", "n", "b", "r", "q", "k" } +}; +/* Converts int to string. Better than using malloc for 3-length strings. */ +char *squarename[64] = { + "a1", "b1", "c1", "d1", "e1", "f1", "g1", "h1", + "a2", "b2", "c2", "d2", "e2", "f2", "g2", "h2", + "a3", "b3", "c3", "d3", "e3", "f3", "g3", "h3", + "a4", "b4", "c4", "d4", "e4", "f4", "g4", "h4", + "a5", "b5", "c5", "d5", "e5", "f5", "g5", "h5", + "a6", "b6", "c6", "d6", "e6", "f6", "g6", "h6", + "a7", "b7", "c7", "d7", "e7", "f7", "g7", "h7", + "a8", "b8", "c8", "d8", "e8", "f8", "g8", "h8" +}; +#ifndef BB_SHIFTFLIP /* see board.h */ +/* Get a bitboard with only one bit set, on a specified square */ +bitboard_t bb_square[64] = { + BB(0x0000000000000001), BB(0x0000000000000002), BB(0x0000000000000004), BB(0x0000000000000008), + BB(0x0000000000000010), BB(0x0000000000000020), BB(0x0000000000000040), BB(0x0000000000000080), + BB(0x0000000000000100), BB(0x0000000000000200), BB(0x0000000000000400), BB(0x0000000000000800), + BB(0x0000000000001000), BB(0x0000000000002000), BB(0x0000000000004000), BB(0x0000000000008000), + BB(0x0000000000010000), BB(0x0000000000020000), BB(0x0000000000040000), BB(0x0000000000080000), + BB(0x0000000000100000), BB(0x0000000000200000), BB(0x0000000000400000), BB(0x0000000000800000), + BB(0x0000000001000000), BB(0x0000000002000000), BB(0x0000000004000000), BB(0x0000000008000000), + BB(0x0000000010000000), BB(0x0000000020000000), BB(0x0000000040000000), BB(0x0000000080000000), + BB(0x0000000100000000), BB(0x0000000200000000), BB(0x0000000400000000), BB(0x0000000800000000), + BB(0x0000001000000000), BB(0x0000002000000000), BB(0x0000004000000000), BB(0x0000008000000000), + BB(0x0000010000000000), BB(0x0000020000000000), BB(0x0000040000000000), BB(0x0000080000000000), + BB(0x0000100000000000), BB(0x0000200000000000), BB(0x0000400000000000), BB(0x0000800000000000), + BB(0x0001000000000000), BB(0x0002000000000000), BB(0x0004000000000000), BB(0x0008000000000000), + BB(0x0010000000000000), BB(0x0020000000000000), BB(0x0040000000000000), BB(0x0080000000000000), + BB(0x0100000000000000), BB(0x0200000000000000), BB(0x0400000000000000), BB(0x0800000000000000), + BB(0x1000000000000000), BB(0x2000000000000000), BB(0x4000000000000000), BB(0x8000000000000000), +}; +/* The bitwise negation of SINGLESQUARE(x) */ +bitboard_t bb_allexcept[64] = { + BB(0xfffffffffffffffe), BB(0xfffffffffffffffd), BB(0xfffffffffffffffb), BB(0xfffffffffffffff7), + BB(0xffffffffffffffef), BB(0xffffffffffffffdf), BB(0xffffffffffffffbf), BB(0xffffffffffffff7f), + BB(0xfffffffffffffeff), BB(0xfffffffffffffdff), BB(0xfffffffffffffbff), BB(0xfffffffffffff7ff), + BB(0xffffffffffffefff), BB(0xffffffffffffdfff), BB(0xffffffffffffbfff), BB(0xffffffffffff7fff), + BB(0xfffffffffffeffff), BB(0xfffffffffffdffff), BB(0xfffffffffffbffff), BB(0xfffffffffff7ffff), + BB(0xffffffffffefffff), BB(0xffffffffffdfffff), BB(0xffffffffffbfffff), BB(0xffffffffff7fffff), + BB(0xfffffffffeffffff), BB(0xfffffffffdffffff), BB(0xfffffffffbffffff), BB(0xfffffffff7ffffff), + BB(0xffffffffefffffff), BB(0xffffffffdfffffff), BB(0xffffffffbfffffff), BB(0xffffffff7fffffff), + BB(0xfffffffeffffffff), BB(0xfffffffdffffffff), BB(0xfffffffbffffffff), BB(0xfffffff7ffffffff), + BB(0xffffffefffffffff), BB(0xffffffdfffffffff), BB(0xffffffbfffffffff), BB(0xffffff7fffffffff), + BB(0xfffffeffffffffff), BB(0xfffffdffffffffff), BB(0xfffffbffffffffff), BB(0xfffff7ffffffffff), + BB(0xffffefffffffffff), BB(0xffffdfffffffffff), BB(0xffffbfffffffffff), BB(0xffff7fffffffffff), + BB(0xfffeffffffffffff), BB(0xfffdffffffffffff), BB(0xfffbffffffffffff), BB(0xfff7ffffffffffff), + BB(0xffefffffffffffff), BB(0xffdfffffffffffff), BB(0xffbfffffffffffff), BB(0xff7fffffffffffff), + BB(0xfeffffffffffffff), BB(0xfdffffffffffffff), BB(0xfbffffffffffffff), BB(0xf7ffffffffffffff), + BB(0xefffffffffffffff), BB(0xdfffffffffffffff), BB(0xbfffffffffffffff), BB(0x7fffffffffffffff), +}; +#endif + +/* Which squares must be unoccupied for COLOR (1st) to castle on SIDE (2nd) */ +static bitboard_t castle_clearsquares[2][2] = { + /* queenside kingside */ + { BB(0x000000000000000e), BB(0x0000000000000060) }, /* white */ + { BB(0x0e00000000000000), BB(0x6000000000000000) } /* black */ +}; +/* Which squares must be unthreatened for COLOR to castle on SIDE */ +static bitboard_t castle_safesquares[2][2] = { + /* queenside kingside */ + { BB(0x000000000000001c), BB(0x0000000000000070) }, /* white */ + { BB(0x1c00000000000000), BB(0x7000000000000000) } /* black */ +}; +/* A mask for the cols adjacent to a given col - for pawn captures, AND with a + * row-mask for the rank you need the pawns to be on */ +bitboard_t bb_adjacentcols[8] = { + BB_FILEB, + BB_FILEA | BB_FILEC, + BB_FILEB | BB_FILED, + BB_FILEC | BB_FILEE, + BB_FILED | BB_FILEF, + BB_FILEE | BB_FILEG, + BB_FILEF | BB_FILEH, + BB_FILEG +}; +/* used for determining when a pawn is passed */ +bitboard_t bb_passedpawnmask[2][64] = { + /* WHITE */ + { + BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), + BB(0x0303030303030000), BB(0x0707070707070000), BB(0x0e0e0e0e0e0e0000), BB(0x1c1c1c1c1c1c0000), BB(0x3838383838380000), BB(0x7070707070700000), BB(0xe0e0e0e0e0e00000), BB(0xc0c0c0c0c0c00000), + BB(0x0303030303000000), BB(0x0707070707000000), BB(0x0e0e0e0e0e000000), BB(0x1c1c1c1c1c000000), BB(0x3838383838000000), BB(0x7070707070000000), BB(0xe0e0e0e0e0000000), BB(0xc0c0c0c0c0000000), + BB(0x0303030300000000), BB(0x0707070700000000), BB(0x0e0e0e0e00000000), BB(0x1c1c1c1c00000000), BB(0x3838383800000000), BB(0x7070707000000000), BB(0xe0e0e0e000000000), BB(0xc0c0c0c000000000), + BB(0x0303030000000000), BB(0x0707070000000000), BB(0x0e0e0e0000000000), BB(0x1c1c1c0000000000), BB(0x3838380000000000), BB(0x7070700000000000), BB(0xe0e0e00000000000), BB(0xc0c0c00000000000), + BB(0x0303000000000000), BB(0x0707000000000000), BB(0x0e0e000000000000), BB(0x1c1c000000000000), BB(0x3838000000000000), BB(0x7070000000000000), BB(0xe0e0000000000000), BB(0xc0c0000000000000), + BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), + BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000) + }, + /* BLACK */ + { + BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), + BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), + BB(0x0000000000000303), BB(0x0000000000000707), BB(0x0000000000000e0e), BB(0x0000000000001c1c), BB(0x0000000000003838), BB(0x0000000000007070), BB(0x000000000000e0e0), BB(0x000000000000c0c0), + BB(0x0000000000030303), BB(0x0000000000070707), BB(0x00000000000e0e0e), BB(0x00000000001c1c1c), BB(0x0000000000383838), BB(0x0000000000707070), BB(0x0000000000e0e0e0), BB(0x0000000000c0c0c0), + BB(0x0000000003030303), BB(0x0000000007070707), BB(0x000000000e0e0e0e), BB(0x000000001c1c1c1c), BB(0x0000000038383838), BB(0x0000000070707070), BB(0x00000000e0e0e0e0), BB(0x00000000c0c0c0c0), + BB(0x0000000303030303), BB(0x0000000707070707), BB(0x0000000e0e0e0e0e), BB(0x0000001c1c1c1c1c), BB(0x0000003838383838), BB(0x0000007070707070), BB(0x000000e0e0e0e0e0), BB(0x000000c0c0c0c0c0), + BB(0x0000030303030303), BB(0x0000070707070707), BB(0x00000e0e0e0e0e0e), BB(0x00001c1c1c1c1c1c), BB(0x0000383838383838), BB(0x0000707070707070), BB(0x0000e0e0e0e0e0e0), BB(0x0000c0c0c0c0c0c0), + BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000) + } +}; + +/* Rotation translation from normal-oriented square indices to square indices + * suitable for setting bits on board_t->occupied{90,45,315}. Note that we + * don't use these for move generation at all, just for setting/clearing bits + * on the occupied boards. */ +#define ROT90SQUAREINDEX(s) rot90squareindex[s] /*(SQUARE(ROW(s),COL(s))) - slower*/ +static int rot90squareindex[64] = { + 0, 8, 16, 24, 32, 40, 48, 56, + 1, 9, 17, 25, 33, 41, 49, 57, + 2, 10, 18, 26, 34, 42, 50, 58, + 3, 11, 19, 27, 35, 43, 51, 59, + 4, 12, 20, 28, 36, 44, 52, 60, + 5, 13, 21, 29, 37, 45, 53, 61, + 6, 14, 22, 30, 38, 46, 54, 62, + 7, 15, 23, 31, 39, 47, 55, 63 +}; +#define ROT45SQUAREINDEX(s) rot45squareindex[s] +static int rot45squareindex[64] = { + 0, 2, 5, 9, 14, 20, 27, 35, + 1, 4, 8, 13, 19, 26, 34, 42, + 3, 7, 12, 18, 25, 33, 41, 48, + 6, 11, 17, 24, 32, 40, 47, 53, + 10, 16, 23, 31, 39, 46, 52, 57, + 15, 22, 30, 38, 45, 51, 56, 60, + 21, 29, 37, 44, 50, 55, 59, 62, + 28, 36, 43, 49, 54, 58, 61, 63 +}; +#define ROT315SQUAREINDEX(s) rot315squareindex[s] +static int rot315squareindex[64] = { + 28, 21, 15, 10, 6, 3, 1, 0, + 36, 29, 22, 16, 11, 7, 4, 2, + 43, 37, 30, 23, 17, 12, 8, 5, + 49, 44, 38, 31, 24, 18, 13, 9, + 54, 50, 45, 39, 32, 25, 19, 14, + 58, 55, 51, 46, 40, 33, 26, 20, + 61, 59, 56, 52, 47, 41, 34, 27, + 63, 62, 60, 57, 53, 48, 42, 35, +}; + +/* for material count */ +extern int16_t eval_piecevalue[6]; + + + +#define ZOBRIST_DEFAULT_HASH 0 +/* Table of random numbers used to generate the zobrist hash. The indices are + * first the color (WHITE/BLACK), then the piece type (PAWN-KING), then the + * square the piece is on (A1-H8) */ +zobrist_t zobrist_piece[2][6][64]; +/* Whose move is it (WHITE/BLACK)? The value present if white has the move. */ +zobrist_t zobrist_tomove; +/* Which square (A1-H8) is the enpassant square? If enpassant is not possible, + * use the key at index 0. */ +zobrist_t zobrist_ep[64]; +/* Can (WHITE/BLACK, first) castle on the (KINGSIDE/QUEENSIDE, second)? If so, + * the value here is xored into the hash. */ +zobrist_t zobrist_castle[2][2]; +/* Have the arrays been initialized? If you reinitialize them in the middle of + * play, the keys will get screwed up. */ +char zobrist_initialized = 0; + +/** + * Initialize the zobrist tables. + */ +void init_zobrist() +{ + int i, j, k; + + /* just in case... */ + if (zobrist_initialized) + { + return; + } + + /* Init the piece position array */ + for (i = 0; i < 2; i++) + { + for (j = 0; j < 6; j++) + { + for (k = 0; k < 64; k++) + { + zobrist_piece[i][j][k] = (zobrist_t)rand64(); + } + } + } + + /* Init the whose-move-is-it value */ + zobrist_tomove = (zobrist_t)rand64(); + + /* Init the enpassant square array */ + for (i = 0; i < 64; i++) + { + zobrist_ep[i] = (zobrist_t)rand64(); + } + + /* Init the castling rights array */ + zobrist_castle[0][0] = (zobrist_t)rand64(); + zobrist_castle[0][1] = (zobrist_t)rand64(); + zobrist_castle[1][0] = (zobrist_t)rand64(); + zobrist_castle[1][1] = (zobrist_t)rand64(); + + zobrist_initialized = 1; + return; +} + +/** + * (Re)generate the zobrist hash for a board, store it in board->hash + * This shouldn't be used every time you change the zobrist, only when + * initializing the board. + */ +void zobrist_gen(board_t *board) +{ + unsigned char color; + piece_t piece; + square_t square; + + int i, j; + bitboard_t pos; + zobrist_t hash = ZOBRIST_DEFAULT_HASH; + + if (board == NULL) + { + return; + } + if (!zobrist_initialized) + { + init_zobrist(); + } + + /* XOR in the zobrist for each piece on the board */ + for (color = 0; color < 2; color++) + { + for (piece = 0; piece < 6; piece++) + { + pos = board->pos[color][piece]; + while (pos) + { + /* Find the first bit */ + square = BITSCAN(pos); + /* throw in the hash */ + hash ^= zobrist_piece[color][piece][square]; + /* and clear the bit */ + pos &= BB_ALLEXCEPT(square); + } + } + } + /* Have the hash reflect special conditions on the board */ + /* En passant */ + hash ^= zobrist_ep[board->ep]; + /* Castling rights */ + for (i = 0; i < 2; i++) + { + for (j = 0; j < 2; j++) + { + if (board->castle[i][j]) + { + hash ^= zobrist_castle[i][j]; + } + } + } + /* Who has the move */ + if (board->tomove == WHITE) + { + hash ^= zobrist_tomove; + } + + board->hash = hash; + return; +} + +/**************************************************************************** + * BITBOARD FUNCTIONS + ****************************************************************************/ +static void board_addmoves_pawn(board_t *, square_t, unsigned char, movelist_t *); +static void board_addmoves_ep(board_t *, unsigned char, movelist_t *); +static void board_addmoves_king(board_t *, square_t, unsigned char, movelist_t *); +static void board_addmoves(board_t *, square_t, piece_t, unsigned char, movelist_t *); + +static void board_addcaptures_pawn(board_t *, square_t, unsigned char, movelist_t *); +static void board_addcaptures_king(board_t *, square_t, unsigned char, movelist_t *); +static void board_addcaptures(board_t *, square_t, piece_t, unsigned char, movelist_t *); +static void board_togglepiece(board_t *, square_t, unsigned char, piece_t); +static void board_regeneratethreatened(board_t *); + +/** + * Generate a fresh board with the default initial starting position. + */ +board_t *board_init() +{ + board_t *board = malloc(sizeof(board_t)); + affirm_msg(board, "Couldn't allocate board"); + + board->pos[WHITE][PAWN] = BB_RANK2; + board->pos[WHITE][KNIGHT] = BB_SQUARE(B1) | BB_SQUARE(G1); + board->pos[WHITE][BISHOP] = BB_SQUARE(C1) | BB_SQUARE(F1); + board->pos[WHITE][ROOK] = BB_SQUARE(A1) | BB_SQUARE(H1); + board->pos[WHITE][QUEEN] = BB_SQUARE(D1); + board->pos[WHITE][KING] = BB_SQUARE(E1); + board->pos[BLACK][PAWN] = BB_RANK7; + board->pos[BLACK][KNIGHT] = BB_SQUARE(B8) | BB_SQUARE(G8); + board->pos[BLACK][BISHOP] = BB_SQUARE(C8) | BB_SQUARE(F8); + board->pos[BLACK][ROOK] = BB_SQUARE(A8) | BB_SQUARE(H8); + board->pos[BLACK][QUEEN] = BB_SQUARE(D8); + board->pos[BLACK][KING] = BB_SQUARE(E8); + + board->piecesofcolor[WHITE] = BB_RANK1 | BB_RANK2; + board->piecesofcolor[BLACK] = BB_RANK8 | BB_RANK7; + + board->attackedby[WHITE] = BB_RANK3 | BB_RANK2 | (BB_RANK1 ^ BB_SQUARE(A1) ^ BB_SQUARE(H1)); + board->attackedby[BLACK] = BB_RANK6 | BB_RANK7 | (BB_RANK8 ^ BB_SQUARE(A8) ^ BB_SQUARE(H8)); + + board->occupied = BB_RANK1 | BB_RANK2 | BB_RANK7 | BB_RANK8; + board->occupied90 = BB_FILEA | BB_FILEB | BB_FILEG | BB_FILEH; + /* These ugly numbers, in contrast to the beautifully simple code + * above, are in fact correct. Check with ./bbtools/rotvisualizer */ + board->occupied45 = BB(0xecc61c3c3c386337); + board->occupied315 = BB(0xfb31861c38618cdf); + + board->ep = 0; + board->castle[WHITE][QUEENSIDE] = 1; + board->castle[WHITE][KINGSIDE] = 1; + board->castle[BLACK][QUEENSIDE] = 1; + board->castle[BLACK][KINGSIDE] = 1; + board->hascastled[WHITE] = 0; + board->hascastled[BLACK] = 0; + board->tomove = WHITE; + board->halfmoves = 0; + board->moves = 0; + board->reps = 0; + + board->material[WHITE] = (8 * eval_piecevalue[PAWN]) + + (2 * eval_piecevalue[KNIGHT]) + + (2 * eval_piecevalue[BISHOP]) + + (2 * eval_piecevalue[ROOK]) + + (eval_piecevalue[QUEEN]) + + (eval_piecevalue[KING]); + board->material[BLACK] = board->material[WHITE]; + + zobrist_gen(board); + + return board; +} + +/** + * Free all memory associated with a board_t. + */ +void board_destroy(board_t *board) +{ + if (board) + { + free(board); + } +} + +/** + * Generates a FEN string for the given position. Free it yourself when you're + * done with it. This function makes no effort to be fast; you shouldn't be + * using it during the search process anyway. + */ +#define FEN_MAX_LENGTH 85 +char *board_fen(board_t *board) +{ + char *fen; + int row, col; + char emptysquares[] = "0"; /* counts consecutive empty squares */ + char halfmove[8]; /* Move clock string - "8 45" maybe */ + piece_t piece; + unsigned char color; + unsigned char empty_end_of_line; + + if (board == NULL) + { + return NULL; + } + + fen = malloc(FEN_MAX_LENGTH + 1); + affirm_msg(fen, "Couldn't allocate board FEN"); + fen[0] = 0; + + for (row = 7; row >= 0; row--) + { + emptysquares[0] = '0'; + empty_end_of_line = 0; + + for (col = 0; col < 8; col++) + { + color = 0; /* really init'ed next line; this makes gcc happy */ + piece = board_pieceatsquare(board, SQUARE(col,row), &color); + if (piece == (piece_t)-1) + { + emptysquares[0]++; + if (col == 7) + { + empty_end_of_line = 1; + } + } + else + { + /* print the emptysquare count if it exists */ + if (emptysquares[0] != '0') + { + strcat(fen, emptysquares); + emptysquares[0] = '0'; + } + strcat(fen, piecename[color][piece]); + } + } + /* we finished printing this row, unless it was empty */ + if (empty_end_of_line) + { + strcat(fen, emptysquares); + } + /* print the row separator */ + strcat(fen, ((row > 0) ? "/" : " ")); + } + /* now all that's left is the flags */ + strcat(fen, ((board->tomove == WHITE) ? "w " : "b ")); + /* castle privileges - this is kinda messy */ + if (!(board->castle[WHITE][QUEENSIDE] || board->castle[WHITE][KINGSIDE] || + board->castle[BLACK][QUEENSIDE] || board->castle[BLACK][KINGSIDE])) + { + strcat(fen, "-"); + } + else + { + if (board->castle[WHITE][KINGSIDE]) strcat(fen, "K"); + if (board->castle[WHITE][QUEENSIDE]) strcat(fen, "Q"); + if (board->castle[BLACK][KINGSIDE]) strcat(fen, "k"); + if (board->castle[BLACK][QUEENSIDE]) strcat(fen, "q"); + } + strcat(fen, " "); + /* enpassant square */ + strcat(fen, ((board->ep != 0) ? squarename[board->ep] : "-")); + strcat(fen, " "); + /* move clocks - 0 for absolute move */ + sprintf(halfmove, "%d %d", board->halfmoves, (board->moves + 1)/2); + strcat(fen, halfmove); + + return fen; +} + +/** + * Gets the piece at the given square index. If the square is empty, -1. + * You should already know that there's a piece there when you call this. + * If the board is NULL or the square is invalid, -2. + * If the third argument is non-null, stores the color of the piece in there + * (unmodified if piece not present). + */ +piece_t board_pieceatsquare(board_t *board, square_t square, unsigned char *c) +{ + bitboard_t mask; + piece_t piece; + unsigned char color; + + if (board == NULL || square > 63) + { + return -2; + } + + mask = BB_SQUARE(square); + + /* find what color the piece is */ + if (board->piecesofcolor[WHITE] & mask) + { + color = WHITE; + } + else if (board->piecesofcolor[BLACK] & mask) + { + color = BLACK; + } + else + { + return -1; + } + + if (c != NULL) + { + *c = color; + } + + /* find what piece type it is */ + piece = 0; + while (!(board->pos[color][piece] & mask)) + { + piece++; + } + return piece; +} + +/** + * Is the player whose move it is in check? (1 if so, 0 if not) + */ +int board_incheck(board_t *board) +{ + return board_colorincheck(board, board->tomove); +} + +/** + * Is the given player in check? (1 if so, 0 if not) + */ +int board_colorincheck(board_t *board, unsigned char color) +{ + return !!(board->pos[color][KING] & board->attackedby[OTHERCOLOR(color)]); +} + +/** + * Check if the player to move is checkmated or stalemated. Returns either + * BOARD_CHECKMATED or BOARD_STALEMATED (from board.h), or 0 if neither. + * This is a very expensive call. Only the engine, not the searcher, should + * use this in-between moves to determine when the game ends. + */ +int board_mated(board_t *board) +{ + int result; + movelist_t moves; + move_t move; + unsigned char color; + + color = board->tomove; + result = board_colorincheck(board, color) ? + BOARD_CHECKMATED : BOARD_STALEMATED; + board_generatemoves(board, &moves); + + + while (!movelist_isempty(&moves)) + { + move = movelist_remove_max(&moves); + /* try the move, see if it puts us in check */ + board_applymove(board, move); + if (!board_colorincheck(board, color)) + { + /* found a legal move */ + board_undomove(board, move); + result = 0; + break; + } + board_undomove(board, move); + } + movelist_destroy(&moves); + return result; +} + +/** + * Is the pawn of given color at given square passed? + */ +int board_pawnpassed(board_t *board, square_t square, unsigned char color) +{ + return !(bb_passedpawnmask[color][square] & + board->pos[OTHERCOLOR(color)][PAWN]); +} + +/** + * Is the given square attacked by any piece of the given color? 1 or 0 + * Presumably the square has the OTHERCOLOR(color)'s king on it + * Note: This is "the" expensive call now that the board library doesn't use + * attacked bitboards. + */ +int board_squareisattacked(board_t *board, square_t square, unsigned char color) +{ + return !!(BB_SQUARE(square) & board->attackedby[color]); +} + +/** + * Returns true if *any* of the given squares are attacked by color. Useful + * for determining castling legality + */ +int board_squaresareattacked(board_t *board, bitboard_t squares, unsigned char color) +{ + return !!(squares & board->attackedby[color]); +} + + +/****************** + * Move generation + ******************/ + +/** + * Given the current board state, returns a bitmask representing all possible + * attacks from a given square assuming a piece of the specified type/color at + * that square. This is not the same as all the moves the piece at that square + * can make - see the special cases: pawns (capture/ep) and kings (castling). + * For pawns, forward pushes are NOT reflected in this mask, but diagonally + * threatened squares ARE, EVEN IF there is a friendly piece there. + * + * Note: Considering how the attack bitboards work, realize that we want to + * keep both attacks on other color's pieces and attacks on same color's + * pieces in here. The board_addmoves functions take care of making sure we + * don't capture our own pieces. + * + * For a cache-friendly optimization, consider taking the slidingpiece's + * index OUT of the occupancy mask before looking up - i.e. for 11101011 and + * the rook is the 3rd index from the right, use 11100011 as a lookup key + * instead, so subsequent accesses with that mask (if you move the rook along + * the column/row, etc) stay in cache. + * UPDATE: It seems to not help. I took it out. + */ +bitboard_t board_attacksfrom(board_t *board, square_t square, piece_t piece, unsigned char color) +{ + /* Used for rook/bishop attack generation */ + int shiftamount; + int diag; + bitboard_t movemask; + bitboard_t rowatk, colatk; + bitboard_t diag45attacks, diag315attacks; + + /* NOTE: We mask with ~piecesofcolor in the calling function. */ + switch (piece) + { + case PAWN: + return pawnattacks[color][square]; + case KNIGHT: + return knightattacks[square]; + case BISHOP: + /* The first table lookup */ + diag = rot45diagindex[square]; + movemask = rot45attacks[(board->occupied45 >> rot45index_shiftamountright[diag]) & 0xFF] + [COL(square)]; + diag45attacks = (movemask << rotresult_shiftamountleft[diag]) + >> rotresult_shiftamountright[diag]; + /* The second table lookup */ + diag = rot315diagindex[square]; + movemask = rot315attacks[((board->occupied315 << rot315index_shiftamountleft[diag]) >> rot315index_shiftamountright[diag]) & 0xFF] + [COL(square)]; + diag315attacks = (movemask << rotresult_shiftamountleft[diag]) + >> rotresult_shiftamountright[diag]; + /* Put them together */ + return (diag45attacks | diag315attacks); + case ROOK: + /* The first table lookup */ + shiftamount = 8 * ROW(square); + movemask = rowattacks[(board->occupied >> shiftamount) & 0xFF][COL(square)]; + rowatk = movemask << shiftamount; + /* The second table lookup */ + shiftamount = COL(square); + movemask = colattacks[(board->occupied90 >> (shiftamount * 8)) & 0xFF][ROW(square)]; + colatk = movemask << shiftamount; + /* Put them together */ + return (rowatk | colatk); + case QUEEN: + return board_attacksfrom(board, square, BISHOP, color) | + board_attacksfrom(board, square, ROOK, color); + case KING: + return kingattacks[square]; + } + /* If we got to here then piece was invalid */ + panic("Invalid piece!"); + return BB(0x0); +} + +/** + * A bitboard of all legal pawn pushes from a square (in the direction + * determined by color) considering the occupied state of the board + */ +bitboard_t board_pawnpushesfrom(board_t *board, square_t square, unsigned char color) +{ + bitboard_t moves, emptysquares; + + emptysquares = ~(board->occupied); + moves = pawnmoves[color][square] & emptysquares; /* can't push if blocked */ + /* handle double push only if a single push was available */ + if (moves) + { + if (color == WHITE) + { + if (ROW(square) == RANK_2) + { + moves |= pawnmoves[color][square + 8] & emptysquares; + } + } + else if (ROW(square) == RANK_7) + { + moves |= pawnmoves[color][square - 8] & emptysquares; + } + } + return moves; +} + +/** + * Generates a linkedlist of "legal" moves for the color to play at the given + * position. The moves are guaranteed legal, with all appropriate flags set, + * suitable for being given to makemove(), EXCEPT it is possible that the move + * might leave the player in check. We leave this task to the searcher - since + * it is necessary to call makemove() to see if a move leaves the player in + * check, and because the searcher calls makemove() anyway; we don't want to + * waste time calling it twice. + * This list needs to be movelist_destroy()ed. If there are no legal moves, + * returns an empty list; if the board is NULL, returns a null pointer. + */ +void board_generatemoves(board_t *board, movelist_t *ml) +{ + bitboard_t position; + piece_t piece; + square_t square; + unsigned char color; + + assert(board); + + color = board->tomove; + movelist_init(ml); + /* we only need to do this part once, not once per pawn */ + if (board->ep) + { + board_addmoves_ep(board, color, ml); + } + /* now do the rest of the moves */ + for (piece = 0; piece < 6; piece++) + { + position = board->pos[color][piece]; + while (position) + { + /* find a piece */ + square = BITSCAN(position); + /* clear the bit */ + position ^= BB_SQUARE(square); + /* special functions for special cases */ + switch (piece) + { + case PAWN: + board_addmoves_pawn(board, square, color, ml); + break; + case KING: + board_addmoves_king(board, square, color, ml); + break; + /* for knights, rooks, bishops, queens, + * we can use attacksfrom() directly */ + default: + board_addmoves(board, square, piece, color, ml); + } + } + } + return; +} + +/** + * The board_addmoves* series of functions take pointers to two linkedlists, + * and add each legal move for the specified piece of the specified color at + * the specified square to the lists, sorted by capture/noncapture. + */ +static void board_addmoves_pawn(board_t *board, square_t square, unsigned char color, + movelist_t *ml) +{ + bitboard_t moves; + square_t destsquare; + piece_t captpiece; + move_t move; + /* note enpassant is handled separately. first we do captures: pawns + * can't move to a square they threaten unless it's a capture */ + moves = pawnattacks[color][square] & /* inlined attacksfrom */ + board->piecesofcolor[OTHERCOLOR(color)]; + while (moves) + { + destsquare = BITSCAN(moves); + moves ^= BB_SQUARE(destsquare); + captpiece = board_pieceatsquare(board, destsquare, NULL); + move = (square << MOV_INDEX_SRC) | + (destsquare << MOV_INDEX_DEST) | + (color << MOV_INDEX_COLOR) | + (0x1 << MOV_INDEX_CAPT) | + (captpiece << MOV_INDEX_CAPTPC) | + (PAWN << MOV_INDEX_PIECE); + /* handle promotions */ + if (ROW(destsquare) == HOMEROW(OTHERCOLOR(color))) + { + move |= (0x1 << MOV_INDEX_PROM); + movelist_add(ml, board->attackedby, (move | (BISHOP << MOV_INDEX_PROMPC))); + movelist_add(ml, board->attackedby, (move | (ROOK << MOV_INDEX_PROMPC))); + movelist_add(ml, board->attackedby, (move | (KNIGHT << MOV_INDEX_PROMPC))); + movelist_add(ml, board->attackedby, (move | (QUEEN << MOV_INDEX_PROMPC))); + } + else /* normal capture */ + { + movelist_add(ml, board->attackedby, move); + } + } + /* now we handle pushes */ + moves = board_pawnpushesfrom(board, square, color); + /* and now we have the proper movemask generated */ + while (moves) + { + destsquare = BITSCAN(moves); + moves ^= BB_SQUARE(destsquare); + move = (square << MOV_INDEX_SRC) | + (destsquare << MOV_INDEX_DEST) | + (color << MOV_INDEX_COLOR) | + (PAWN << MOV_INDEX_PIECE); + /* handle promotions - add to the captures list because pawn + * promotions, like captures, change the board's material */ + if (ROW(destsquare) == HOMEROW(OTHERCOLOR(color))) + { + move |= (0x1 << MOV_INDEX_PROM); + movelist_add(ml, board->attackedby, (move | (BISHOP << MOV_INDEX_PROMPC))); + movelist_add(ml, board->attackedby, (move | (ROOK << MOV_INDEX_PROMPC))); + movelist_add(ml, board->attackedby, (move | (KNIGHT << MOV_INDEX_PROMPC))); + movelist_add(ml, board->attackedby, (move | (QUEEN << MOV_INDEX_PROMPC))); + } + else /* normal push */ + { + movelist_add(ml, board->attackedby, move); + } + } + /* and we're done, phew */ + return; +} +/* don't call this if board->ep = 0 */ +static void board_addmoves_ep(board_t *board, unsigned char color, movelist_t *ml) +{ + bitboard_t pawns; + square_t fromsquare; /* we know where the dest is; we need this now */ + move_t move; + + assert(board->ep); + + /* find all pawns eligible to make the capture */ + pawns = bb_adjacentcols[COL(board->ep)] & /* the col the pawn is on */ + BB_EP_FROMRANK(color) & /* the rank a pawn needs to be on */ + board->pos[color][PAWN] /* where your pawns actually are */; + while (pawns) + { + fromsquare = BITSCAN(pawns); + pawns ^= BB_SQUARE(fromsquare); + move = (fromsquare << MOV_INDEX_SRC) | + (board->ep << MOV_INDEX_DEST) | + (0x1 << MOV_INDEX_EP) | + (0x1 << MOV_INDEX_CAPT) | + (PAWN << MOV_INDEX_CAPTPC) | + (PAWN << MOV_INDEX_PIECE); + movelist_add(ml, board->attackedby, move); + } + return; +} +/* wrapper for board_addmoves() with a special case handler for castling */ +static void board_addmoves_king(board_t *board, square_t square, unsigned char color, + movelist_t *ml) +{ + move_t move; + square_t destsquare; + int side; + /* used in the second half */ + bitboard_t moves, capts; + piece_t captpiece; + + /* deal with castling - iterate side={0,1} */ + for (side = 0; side < 2; side++) + { + if (board->castle[color][side]) + { + /* If the squares are occupied (1st two lines) or + * threatened (2nd two) then we cannot castle */ + if (!((castle_clearsquares[color][side] & + board->occupied) || + board_squaresareattacked(board, castle_safesquares[color][side], + OTHERCOLOR(color)))) + { + /* find where the king will end up */ + destsquare = SQUARE(CASTLE_DEST_COL(side), + HOMEROW(color)); + /* generate and add the move */ + move = (square << MOV_INDEX_SRC) | + (destsquare << MOV_INDEX_DEST) | + (color << MOV_INDEX_COLOR) | + (0x1 << MOV_INDEX_CASTLE) | + (KING << MOV_INDEX_PIECE); + movelist_add(ml, board->attackedby, move); + } + } + } + /* now the special case is out of the way, the rest is simple. this + * could be a call to board_addmoves, but for move ordering purposes + * we do it separately. also, if we filter out suicide moves here, + * we avoid wasting time with applymove() in the searcher before + * seeing if the move is legal. */ + /* inlined attacksfrom */ + moves = kingattacks[square] & (~(board->piecesofcolor[color])); + /* here's the special part - we can't move the king anywhere where it + * will be in check - note, this still produces an illegal move if the + * king walks straight backward from a sliding piece, but we're only + * producing pseudo-legal moves, so this is merely an optimization. + * the movelist relies on not producing an obvious king-hang move. */ + moves &= (~(board->attackedby[OTHERCOLOR(color)])); + /* the rest is the same as board_addmoves */ + capts = moves & board->piecesofcolor[OTHERCOLOR(color)]; + moves ^= capts; + /* that's a lie - the other special thing we do here is ordering so + * the king moves/capts are grouped with the pawn moves/capts */ + while (capts) + { + /* find and clear a bit */ + destsquare = BITSCAN(capts); + capts ^= BB_SQUARE(destsquare); + /* find what piece was captured */ + captpiece = board_pieceatsquare(board, destsquare, NULL); + /* generate the move_t */ + move = (square << MOV_INDEX_SRC) | /* from square */ + (destsquare << MOV_INDEX_DEST) | /* to square */ + (color << MOV_INDEX_COLOR) | /* color flag */ + (0x1 << MOV_INDEX_CAPT) | /* capture flag */ + (captpiece << MOV_INDEX_CAPTPC) | /* captured piece */ + (KING << MOV_INDEX_PIECE); /* our piece */ + /* and add it to the list */ + movelist_add(ml, board->attackedby, move); + } + /* then process noncapture moves */ + while (moves) + { + /* find and clear a bit */ + destsquare = BITSCAN(moves); + moves ^= BB_SQUARE(destsquare); + /* generate the move_t */ + move = (square << MOV_INDEX_SRC) | /* from square */ + (destsquare << MOV_INDEX_DEST) | /* to square */ + (color << MOV_INDEX_COLOR) | /* color flag */ + (KING << MOV_INDEX_PIECE); /* our piece */ + /* and add it to the list */ + movelist_add(ml, board->attackedby, move); + } + + return; +} +/* for non-special-case pieces: knight bishop rook queen. see above comment */ +static void board_addmoves(board_t *board, square_t square, piece_t piece, unsigned char color, + movelist_t *ml) +{ + bitboard_t moves, capts; + square_t destsquare; + piece_t captpiece; + move_t move; + + /* find all destination squares -- all attacked squares, but can't + * capture our own pieces */ + moves = board_attacksfrom(board, square, piece, color) & (~(board->piecesofcolor[color])); + /* separate captures from noncaptures */ + capts = moves & board->piecesofcolor[OTHERCOLOR(color)]; + moves ^= capts; + /* process captures first */ + while (capts) + { + /* find and clear a bit */ + destsquare = BITSCAN(capts); + capts ^= BB_SQUARE(destsquare); + /* find what piece was captured */ + captpiece = board_pieceatsquare(board, destsquare, NULL); + /* generate the move_t */ + move = (square << MOV_INDEX_SRC) | /* from square */ + (destsquare << MOV_INDEX_DEST) | /* to square */ + (color << MOV_INDEX_COLOR) | /* color flag */ + (0x1 << MOV_INDEX_CAPT) | /* capture flag */ + (captpiece << MOV_INDEX_CAPTPC) | /* captured piece */ + (piece << MOV_INDEX_PIECE); /* our piece */ + /* and add it to the list */ + movelist_add(ml, board->attackedby, move); + } + /* then process noncapture moves */ + while (moves) + { + /* find and clear a bit */ + destsquare = BITSCAN(moves); + moves ^= BB_SQUARE(destsquare); + /* generate the move_t */ + move = (square << MOV_INDEX_SRC) | /* from square */ + (destsquare << MOV_INDEX_DEST) | /* to square */ + (color << MOV_INDEX_COLOR) | /* color flag */ + (piece << MOV_INDEX_PIECE); /* our piece */ + /* and add it to the list */ + movelist_add(ml, board->attackedby, move); + } + return; +} + +/** + * The same as board_generatemoves, except we generate only captures. This is + * optimized to not even think about noncapture moves to be especially fast + * for quiescence searching. + */ +void board_generatecaptures(board_t *board, movelist_t *ml) +{ + bitboard_t position; + piece_t piece; + square_t square; + unsigned char color; + + assert(board); + + color = board->tomove; + movelist_init(ml); + /* same call as in addmoves... ep is always a capture */ + if (board->ep) + { + //XXX: Take this out, as it won't help that much in quiescence? Depends on how fast it is + board_addmoves_ep(board, color, ml); + } + for (piece = 0; piece < 6; piece++) + { + position = board->pos[color][piece]; + while (position) + { + /* find a piece */ + square = BITSCAN(position); + /* clear the bit */ + position ^= BB_SQUARE(square); + switch (piece) + { + case PAWN: + board_addcaptures_pawn(board, square, color, ml); + break; + case KING: + board_addcaptures_king(board, square, color, ml); + break; + default: + board_addcaptures(board, square, piece, color, ml); + } + } + } + return; +} + +static void board_addcaptures_pawn(board_t *board, square_t square, unsigned char color, movelist_t *ml) +{ + bitboard_t moves; + square_t destsquare; + piece_t captpiece; + move_t move; + /* captures */ + moves = pawnattacks[color][square] & /* inlined attacksfrom */ + board->piecesofcolor[OTHERCOLOR(color)]; + while (moves) + { + destsquare = BITSCAN(moves); + moves ^= BB_SQUARE(destsquare); + captpiece = board_pieceatsquare(board, destsquare, NULL); + move = (square << MOV_INDEX_SRC) | + (destsquare << MOV_INDEX_DEST) | + (color << MOV_INDEX_COLOR) | + (0x1 << MOV_INDEX_CAPT) | + (captpiece << MOV_INDEX_CAPTPC) | + (PAWN << MOV_INDEX_PIECE); + /* handle promotions */ + if (ROW(destsquare) == HOMEROW(OTHERCOLOR(color))) + { + move |= (0x1 << MOV_INDEX_PROM); + movelist_add(ml, board->attackedby, (move | (BISHOP << MOV_INDEX_PROMPC))); + movelist_add(ml, board->attackedby, (move | (ROOK << MOV_INDEX_PROMPC))); + movelist_add(ml, board->attackedby, (move | (KNIGHT << MOV_INDEX_PROMPC))); + movelist_add(ml, board->attackedby, (move | (QUEEN << MOV_INDEX_PROMPC))); + } + else /* normal capture */ + { + movelist_add(ml, board->attackedby, move); + } + } + /* now we handle pushes only if it's a passed pawn */ + if (board_pawnpassed(board, square, color)) + { + moves = board_pawnpushesfrom(board, square, color); + /* and now we have the proper movemask generated */ + while (moves) + { + destsquare = BITSCAN(moves); + moves ^= BB_SQUARE(destsquare); + move = (square << MOV_INDEX_SRC) | + (destsquare << MOV_INDEX_DEST) | + (color << MOV_INDEX_COLOR) | + (PAWN << MOV_INDEX_PIECE); + /* handle promotions */ + if (ROW(destsquare) == HOMEROW(OTHERCOLOR(color))) + { + move |= (0x1 << MOV_INDEX_PROM); + movelist_add(ml, board->attackedby, (move | (BISHOP << MOV_INDEX_PROMPC))); + movelist_add(ml, board->attackedby, (move | (ROOK << MOV_INDEX_PROMPC))); + movelist_add(ml, board->attackedby, (move | (KNIGHT << MOV_INDEX_PROMPC))); + movelist_add(ml, board->attackedby, (move | (QUEEN << MOV_INDEX_PROMPC))); + } + else /* normal push */ + { + movelist_add(ml, board->attackedby, move); + } + } + } + return; +} + +static void board_addcaptures_king(board_t *board, square_t square, unsigned char color, movelist_t *ml) +{ + move_t move; + square_t destsquare; + bitboard_t moves, capts; + piece_t captpiece; + + /* No dealing with castling! :D this is the same as addcaptures() but + * again we do the special thing */ + /* inlined attacksfrom */ + moves = kingattacks[square] & (~(board->piecesofcolor[color])); + moves &= (~(board->attackedby[OTHERCOLOR(color)])); + capts = moves & board->piecesofcolor[OTHERCOLOR(color)]; + moves ^= capts; + /* like in regular movegen, captures by king go at the beginning */ + while (capts) + { + /* find and clear a bit */ + destsquare = BITSCAN(capts); + capts ^= BB_SQUARE(destsquare); + /* find what piece was captured */ + captpiece = board_pieceatsquare(board, destsquare, NULL); + /* generate the move_t */ + move = (square << MOV_INDEX_SRC) | /* from square */ + (destsquare << MOV_INDEX_DEST) | /* to square */ + (color << MOV_INDEX_COLOR) | /* color flag */ + (0x1 << MOV_INDEX_CAPT) | /* capture flag */ + (captpiece << MOV_INDEX_CAPTPC) | /* captured piece */ + (KING << MOV_INDEX_PIECE); /* our piece */ + /* and add it to the list */ + movelist_add(ml, board->attackedby, move); + } + return; +} + +static void board_addcaptures(board_t *board, square_t square, piece_t piece, unsigned char color, movelist_t *ml) +{ + bitboard_t moves, capts; + square_t destsquare; + piece_t captpiece; + move_t move; + + /* find all destination squares -- all attacked squares, but can't + * capture our own pieces */ + moves = board_attacksfrom(board, square, piece, color) & + (~(board->piecesofcolor[color])); + /* separate captures from noncaptures */ + capts = moves & board->piecesofcolor[OTHERCOLOR(color)]; + moves ^= capts; + /* process captures first */ + while (capts) + { + /* find and clear a bit */ + destsquare = BITSCAN(capts); + capts ^= BB_SQUARE(destsquare); + /* find what piece was captured */ + captpiece = board_pieceatsquare(board, destsquare, NULL); + /* generate the move_t */ + move = (square << MOV_INDEX_SRC) | /* from square */ + (destsquare << MOV_INDEX_DEST) | /* to square */ + (color << MOV_INDEX_COLOR) | /* color flag */ + (0x1 << MOV_INDEX_CAPT) | /* capture flag */ + (captpiece << MOV_INDEX_CAPTPC) | /* captured piece */ + (piece << MOV_INDEX_PIECE); /* our piece */ + /* and add it to the list */ + movelist_add(ml, board->attackedby, move); + } + return; +} + + +/*********************** + * Changing board state + ***********************/ + +/** + * Given a move, which MUST be properly formatted AND legal (only use moves + * returned by board_generatemoves() or move_islegal() here), applies the move + * to change the board position. Updates the zobrist hash, undo stacks, + * everything. + */ +void board_applymove(board_t *board, move_t move) +{ + square_t rooksrc, rookdest; /* how the rook moves in castling */ + square_t epcapture; /* where a pawn will disappear from */ + int i; + + /* save history. */ + history_t *h = &board->history[board->moves]; + affirm(board->moves < HISTORY_STACK_SIZE); + h->hash = board->hash; + h->attackedby[WHITE] = board->attackedby[WHITE]; + h->attackedby[BLACK] = board->attackedby[BLACK]; + h->castle[WHITE][QUEENSIDE] = board->castle[WHITE][QUEENSIDE]; + h->castle[WHITE][KINGSIDE] = board->castle[WHITE][KINGSIDE]; + h->castle[BLACK][QUEENSIDE] = board->castle[BLACK][QUEENSIDE]; + h->castle[BLACK][KINGSIDE] = board->castle[BLACK][KINGSIDE]; + h->ep = board->ep; + h->halfmoves = board->halfmoves; + h->reps = board->reps; + h->move = move; + + /* cleanly handle null-move */ + if (move == 0) + { + /* clear ep square */ + board->hash ^= zobrist_ep[board->ep]; + board->ep = 0; + board->hash ^= zobrist_ep[board->ep]; + /* update the move clock */ + board->halfmoves++; + board->moves++; + /* null move is illegal, so it can't cause a threefold draw */ + board->reps = 0; + /* switch who has the move */ + board->tomove = OTHERCOLOR(board->tomove); + board->hash ^= zobrist_tomove; + return; + } + + assert(MOV_PIECE(move) >= 0 && MOV_PIECE(move) < 6); + + /* Take care of captures - we need to remove the captured piece. */ + if (MOV_CAPT(move)) + { + /* special case - en passant - square behind the dest square */ + if (MOV_EP(move)) + { + assert(ROW(MOV_SRC(move)) == 4 - board->tomove); + /* find where the pawn disappears from */ + epcapture = (board->tomove == WHITE) ? + (MOV_DEST(move) - 8) : + (MOV_DEST(move) + 8); + /* kill the pawn */ + board_togglepiece(board, epcapture, + OTHERCOLOR(board->tomove), PAWN); + /* change the material count */ + board->material[OTHERCOLOR(board->tomove)] -= + eval_piecevalue[PAWN]; + } + /* standard capture - square is the dest square */ + else + { + board_togglepiece(board, MOV_DEST(move), + OTHERCOLOR(board->tomove), + MOV_CAPTPC(move)); + /* If the captured piece is a rook on its home square, + * and the player was still able to castle that side, + * we need to clear the castle privileges there */ + if (MOV_CAPTPC(move) == ROOK && + ROW(MOV_DEST(move)) == HOMEROW(OTHERCOLOR(board->tomove)) && + (COL(MOV_DEST(move)) == COL_H || + COL(MOV_DEST(move)) == COL_A)) + { + /* (COLUMN == COL_H) will evaluate to 1 if on + * KINGSIDE (this depends on KINGSIDE == 1) */ + unsigned char side = (COL(MOV_DEST(move)) == COL_H); + /* if castle rights is already gone there, we + * don't do anything. this is important when + * toggling the zobrist */ + if (board->castle[OTHERCOLOR(board->tomove)][side]) + { + board->castle[OTHERCOLOR(board->tomove)][side] = 0; + board->hash ^= zobrist_castle[OTHERCOLOR(board->tomove)] + [side]; + } + + } + /* change the material count */ + board->material[OTHERCOLOR(board->tomove)] -= + eval_piecevalue[MOV_CAPTPC(move)]; + } + board->halfmoves = 0; + } + /* here we detect irreversible moves for the halfmove clock */ + else + { + if (MOV_PIECE(move) == PAWN) + { + board->halfmoves = 0; + } + else + { + board->halfmoves++; + } + } + /* the game clock as well */ + board->moves++; + + /* castling, need to move the rook. castle privileges handled below */ + if (MOV_CASTLE(move)) + { + /* detect kingside vs queenside */ + if (COL(MOV_DEST(move)) == COL_G) + { + rooksrc = SQUARE(COL_H,HOMEROW(board->tomove)); + rookdest = SQUARE(COL_F,HOMEROW(board->tomove)); + } + else + { + rooksrc = SQUARE(COL_A,HOMEROW(board->tomove)); + rookdest = SQUARE(COL_D,HOMEROW(board->tomove)); + } + /* and move the rook */ + board_togglepiece(board, rooksrc, board->tomove, ROOK); + board_togglepiece(board, rookdest, board->tomove, ROOK); + /* set the flag */ + board->hascastled[board->tomove] = 1; + } + + /* here we move the moving piece itself; in the former case it turns + * into a different type of piece */ + board_togglepiece(board, MOV_SRC(move), board->tomove, + MOV_PIECE(move)); + if (MOV_PROM(move)) + { + assert(ROW(MOV_DEST(move)) == + HOMEROW(OTHERCOLOR(board->tomove))); + board_togglepiece(board, MOV_DEST(move), board->tomove, + MOV_PROMPC(move)); + /* and of course account for this in the material count */ + board->material[board->tomove] += + (eval_piecevalue[MOV_PROMPC(move)] - + eval_piecevalue[PAWN]); + } + else + { + board_togglepiece(board, MOV_DEST(move), board->tomove, + MOV_PIECE(move)); + } + + /* detect an enpassantable move */ + if (MOV_PIECE(move) == PAWN) + { + /* if the difference between the square values is 16 not 8 + * then it was a double push */ + if ((board->tomove == WHITE) && + ((MOV_DEST(move) - MOV_SRC(move)) == 16)) + { + /* clear the old ep status in the hash */ + board->hash ^= zobrist_ep[board->ep]; + /* set the new value */ + board->ep = MOV_SRC(move) + 8; + /* throw in the new key */ + board->hash ^= zobrist_ep[board->ep]; + } + else if ((board->tomove == BLACK) && + ((MOV_SRC(move) - MOV_DEST(move)) == 16)) + { + board->hash ^= zobrist_ep[board->ep]; + board->ep = MOV_DEST(move) + 8; + board->hash ^= zobrist_ep[board->ep]; + } + else + { + board->hash ^= zobrist_ep[board->ep]; + board->ep = 0; + board->hash ^= zobrist_ep[board->ep]; + } + } + /* not a pawn move. ep square goes away. */ + else + { + board->hash ^= zobrist_ep[board->ep]; + board->ep = 0; + board->hash ^= zobrist_ep[board->ep]; + /* handle castling rights */ + if (MOV_PIECE(move) == KING) + { + if (board->castle[board->tomove][KINGSIDE]) + { + board->castle[board->tomove][KINGSIDE] = 0; + board->hash ^= zobrist_castle[board->tomove][KINGSIDE]; + } + if (board->castle[board->tomove][QUEENSIDE]) + { + board->castle[board->tomove][QUEENSIDE] = 0; + board->hash ^= zobrist_castle[board->tomove][QUEENSIDE]; + } + } + else if (MOV_PIECE(move) == ROOK) + { + if ((board->castle[board->tomove][KINGSIDE]) && + (COL(MOV_SRC(move)) == COL_H)) + { + board->castle[board->tomove][KINGSIDE] = 0; + board->hash ^= zobrist_castle[board->tomove][KINGSIDE]; + } + else if ((board->castle[board->tomove][QUEENSIDE]) && + (COL(MOV_SRC(move)) == COL_A)) + { + board->castle[board->tomove][QUEENSIDE] = 0; + board->hash ^= zobrist_castle[board->tomove][QUEENSIDE]; + } + } + } + + /* switch who has the move */ + board->tomove = OTHERCOLOR(board->tomove); + board->hash ^= zobrist_tomove; + + /* calculate repetition count */ + board->reps = 0; + for (i = 1; i <= board->halfmoves; i++) + { + if (board->history[board->moves - i].hash == board->hash) + { + board->reps = board->history[board->moves - i].reps+1; + break; + } + } + + /* and finally */ + board_regeneratethreatened(board); + return; +} + +/** + * Go back one move. The cleaner implementation is to keep a stack of the + * moves, but it's faster to have the searcher/legalitychecker just pass in + * the move again rather than mucking about with data structures. + * Note if you pass in a move different from the one that was most recently + * made, the board state will choke and die horribly. + */ +void board_undomove(board_t *board, move_t move) +{ + square_t rooksrc, rookdest, epcapture; + + /* switch who has the move */ + board->tomove = OTHERCOLOR(board->tomove); + board->hash ^= zobrist_tomove; + + /* cleanly handle null-move */ + if (move == 0) + { + board->moves--; + board->halfmoves--; + board->hash ^= zobrist_ep[board->ep]; + board->ep = board->history[board->moves].ep; + board->hash ^= zobrist_ep[board->ep]; + board->reps = board->history[board->moves].reps; + return; + } + + /* The non-special things (see bottom of function for special things) + * are basically applymove in reverse. First move the piece back. */ + board_togglepiece(board, MOV_SRC(move), board->tomove, MOV_PIECE(move)); + if (MOV_PROM(move)) + { + board_togglepiece(board, MOV_DEST(move), board->tomove, + MOV_PROMPC(move)); + /* material count */ + board->material[board->tomove] -= + (eval_piecevalue[MOV_PROMPC(move)] - + eval_piecevalue[PAWN]); + } + else + { + board_togglepiece(board, MOV_DEST(move), board->tomove, + MOV_PIECE(move)); + } + /* castling, need to move the rook back. */ + if (MOV_CASTLE(move)) + { + /* detect kingside vs queenside */ + if (COL(MOV_DEST(move)) == COL_G) + { + /* note src is where it needs to end up because we're + * moving backwards not forwards */ + rooksrc = SQUARE(COL_H,HOMEROW(board->tomove)); + rookdest = SQUARE(COL_F,HOMEROW(board->tomove)); + } + else + { + rooksrc = SQUARE(COL_A,HOMEROW(board->tomove)); + rookdest = SQUARE(COL_D,HOMEROW(board->tomove)); + } + /* and move the rook */ + board_togglepiece(board, rooksrc, board->tomove, ROOK); + board_togglepiece(board, rookdest, board->tomove, ROOK); + /* flag */ + board->hascastled[board->tomove] = 0; + } + /* for captures, put the captured piece back */ + if (MOV_CAPT(move)) + { + /* special case - en passant - square behind the dest square */ + if (MOV_EP(move)) + { + epcapture = (board->tomove == WHITE) ? + (MOV_DEST(move) - 8) : + (MOV_DEST(move) + 8); + board_togglepiece(board, epcapture, + OTHERCOLOR(board->tomove), PAWN); + board->material[OTHERCOLOR(board->tomove)] += + eval_piecevalue[PAWN]; + } + /* standard capture - square is the dest square */ + else + { + board_togglepiece(board, MOV_DEST(move), + OTHERCOLOR(board->tomove), + MOV_CAPTPC(move)); + board->material[OTHERCOLOR(board->tomove)] += + eval_piecevalue[MOV_CAPTPC(move)]; + } + } + + /* decrement the game clock */ + board->moves--; + + /* Get the previous special board state information from the stacks */ + board->attackedby[WHITE] = board->history[board->moves].attackedby[WHITE]; + board->attackedby[BLACK] = board->history[board->moves].attackedby[BLACK]; + + /* clear the old castle keys */ + if (board->castle[WHITE][QUEENSIDE]) { board->hash ^= zobrist_castle[WHITE][QUEENSIDE]; } + if (board->castle[WHITE][KINGSIDE]) { board->hash ^= zobrist_castle[WHITE][KINGSIDE]; } + if (board->castle[BLACK][QUEENSIDE]) { board->hash ^= zobrist_castle[BLACK][QUEENSIDE]; } + if (board->castle[BLACK][KINGSIDE]) { board->hash ^= zobrist_castle[BLACK][KINGSIDE]; } + /* set the new castle rights */ + board->castle[WHITE][QUEENSIDE] = board->history[board->moves].castle[WHITE][QUEENSIDE]; + board->castle[WHITE][KINGSIDE] = board->history[board->moves].castle[WHITE][KINGSIDE]; + board->castle[BLACK][QUEENSIDE] = board->history[board->moves].castle[BLACK][QUEENSIDE]; + board->castle[BLACK][KINGSIDE] = board->history[board->moves].castle[BLACK][KINGSIDE]; + /* set the new castle keys */ + if (board->castle[WHITE][QUEENSIDE]) { board->hash ^= zobrist_castle[WHITE][QUEENSIDE]; } + if (board->castle[WHITE][KINGSIDE]) { board->hash ^= zobrist_castle[WHITE][KINGSIDE]; } + if (board->castle[BLACK][QUEENSIDE]) { board->hash ^= zobrist_castle[BLACK][QUEENSIDE]; } + if (board->castle[BLACK][KINGSIDE]) { board->hash ^= zobrist_castle[BLACK][KINGSIDE]; } + + /* restore ep information */ + board->hash ^= zobrist_ep[board->ep]; + board->ep = board->history[board->moves].ep; + board->hash ^= zobrist_ep[board->ep]; + + /* set the halfmove clock */ + board->halfmoves = board->history[board->moves].halfmoves; + + /* and repetitions */ + board->reps = board->history[board->moves].reps; + + /* consistency check */ + assert(board->hash == board->history[board->moves].hash); + assert(move == board->history[board->moves].move); + return; +} + +/** + * The togglepiece function is a wrapper to simplify moving pieces around on + * the board. They modify the bits in the piece-specific position masks, the + * all-pieces-of-one-color mask, and in the four occupied boards, and adjust + * the zobrist hash. + */ +static void board_togglepiece(board_t *board, square_t square, + unsigned char color, piece_t piece) +{ + /* no other piece ought be on this square */ + assert(!(board->occupied & BB_SQUARE(square) & + ~board->pos[color][piece])); + /* piece-specific position mask */ + board->pos[color][piece] ^= BB_SQUARE(square); + + /* all the color's pieces */ + board->piecesofcolor[color] ^= BB_SQUARE(square); + + /* general occupied masks */ + board->occupied ^= BB_SQUARE(square); + board->occupied90 ^= BB_SQUARE(ROT90SQUAREINDEX(square)); + board->occupied45 ^= BB_SQUARE(ROT45SQUAREINDEX(square)); + board->occupied315 ^= BB_SQUARE(ROT315SQUAREINDEX(square)); + + /* adjust the zobrist */ + board->hash ^= zobrist_piece[color][piece][square]; +} + +/** + * This hashtable stores threatened square masks so we don't have to always + * regenerate them. + */ +typedef struct { + bitboard_t key; + bitboard_t white; + bitboard_t black; +} regen_entry_t; + +#ifndef REGEN_NUM_BUCKETS +#define REGEN_NUM_BUCKETS (32 * 1024 * 1024 / sizeof(regen_entry_t)) // 32 MB +#endif +static regen_entry_t regen_array[REGEN_NUM_BUCKETS]; + +static void regen_add(bitboard_t key, bitboard_t white, bitboard_t black) +{ + unsigned long bucket = key % REGEN_NUM_BUCKETS; + regen_array[bucket].key = key; + regen_array[bucket].white = white; + regen_array[bucket].black = black; +} + +static int regen_get(bitboard_t key, bitboard_t *white, bitboard_t *black) +{ + unsigned long bucket = key % REGEN_NUM_BUCKETS; + if (regen_array[bucket].key == key) + { + *white = regen_array[bucket].white; + *black = regen_array[bucket].black; + return 1; + } + return 0; +} + +int regen_hits = 0; +int regen_misses = 0; + +/** + * Regenerate the threatened squares masks for both sides. Should be used when + * a move is made. Don't use in undomove, use the special stacks instead + */ +static void board_regeneratethreatened(board_t *board) +{ + bitboard_t mask; + bitboard_t position; + piece_t piece; + square_t square; + + /* check hashtable */ + if (regen_get(board->hash, + &board->attackedby[WHITE], &board->attackedby[BLACK])) + { + regen_hits++; + return; + } + + /******** + * White + ********/ + mask = BB(0x0); + /* pawn threatened can be done for all pawns at once */ + mask |= board_pawnattacks(board->pos[WHITE][PAWN], WHITE); + /* Knights and kings manually inlined */ + position = board->pos[WHITE][KNIGHT]; + while (position) + { + square = BITSCAN(position); + position ^= BB_SQUARE(square); + mask |= knightattacks[square]; + } + position = board->pos[WHITE][KING]; + while(position) + { + square = BITSCAN(position); + position ^= BB_SQUARE(square); + mask |= kingattacks[square]; + } + /* other piece threatened */ + for (piece = 2; piece < 5; piece++) + { + position = board->pos[WHITE][piece]; + /* keep going until we've found all the pieces */ + while (position) + { + /* Find one of the pieces, clear its bit */ + square = BITSCAN(position); + position ^= BB_SQUARE(square); + /* Put the attacks from this square in the mask */ + mask |= board_attacksfrom(board, square, piece, WHITE); + } + } + board->attackedby[WHITE] = mask; + /******** + * Black + ********/ + mask = BB(0x0); + /* pawn threatened can be done for all pawns at once */ + mask |= board_pawnattacks(board->pos[BLACK][PAWN], BLACK); + /* Knights and kings manually inlined */ + position = board->pos[BLACK][KNIGHT]; + while (position) + { + square = BITSCAN(position); + position ^= BB_SQUARE(square); + mask |= knightattacks[square]; + } + position = board->pos[BLACK][KING]; + while(position) + { + square = BITSCAN(position); + position ^= BB_SQUARE(square); + mask |= kingattacks[square]; + } + /* other piece threatened */ + for (piece = 2; piece < 5; piece++) + { + position = board->pos[BLACK][piece]; + /* keep going until we've found all the pieces */ + while (position) + { + /* Find one of the pieces, clear its bit */ + square = BITSCAN(position); + position ^= BB_SQUARE(square); + /* Put the attacks from this square in the mask */ + mask |= board_attacksfrom(board, square, piece, BLACK); + } + } + board->attackedby[BLACK] = mask; + + /* save to hashtable */ + regen_add(board->hash, board->attackedby[WHITE], board->attackedby[BLACK]); + regen_misses++; + + return; +} + +/** + * Get a bitmap of all squares attacked by the pawns in the given position of + * the given color. Used by regenthreatened, and also in pawnstructure eval + */ +bitboard_t board_pawnattacks(bitboard_t pawns, unsigned char color) +{ + /* a-pawns don't attack left; h-pawns don't attack right */ + if (color == WHITE) + { + return ((pawns & ~BB_FILEA) << 7) | ((pawns & ~BB_FILEH) << 9); + } + else + { + return ((pawns & ~BB_FILEA) >> 9) | ((pawns & ~BB_FILEH) >> 7); + } +} + +/** + * Is the current position a threefold draw? + */ +int board_threefold_draw(board_t *board) +{ + return board->reps >= 2; +} + +/**************************************************************************** + * END: BITBOARD FUNCTIONS + * BEGIN: MOVE FUNCTIONS + ****************************************************************************/ + +static move_t move_checksuicide(board_t *, move_t, char **); + +/** + * Parses computer friendly ("d7c8N" or "e1g1") notation to generate a simple + * move_t template. Will return 0 on a malformatted move (note 0 is never a + * valid move_t). This will only set the prom flag, not castle/ep/capt. As a + * result, the resultant move is not suitable for throwing directly into + * applyMove. + */ +move_t move_fromstring(char *str) +{ + size_t length = strlen(str); + move_t move = 0; + + /* check for malformatted move string */ + if (length < 4 || length > 5 || /* too short/long */ + !(str[0] >= 'a' && str[0] <= 'h') || /* bad src/dest squares */ + !(str[1] >= '1' && str[1] <= '8') || + !(str[2] >= 'a' && str[2] <= 'h') || + !(str[3] >= '1' && str[3] <= '8') || + (length == 5 && /* bad promotion piece */ + !(str[4] == 'N' || str[4] == 'B' || + str[4] == 'R' || str[4] == 'Q' || + str[4] == 'n' || str[4] == 'b' || + str[4] == 'r' || str[4] == 'q'))) + { + return (move_t)0; + } + + /* set the src and dest */ + move |= SQUARE((str[0] - 'a'), (str[1] - '1')) << MOV_INDEX_SRC; + move |= SQUARE((str[2] - 'a'), (str[3] - '1')) << MOV_INDEX_DEST; + + /* promotion */ + if (length == 5) + { + move |= 1 << MOV_INDEX_PROM; /* set the flag */ + switch(str[4]) + { + case 'N': + case 'n': + move |= KNIGHT << MOV_INDEX_PROMPC; + break; + case 'B': + case 'b': + move |= BISHOP << MOV_INDEX_PROMPC; + break; + case 'R': + case 'r': + move |= ROOK << MOV_INDEX_PROMPC; + break; + default: + move |= QUEEN << MOV_INDEX_PROMPC; + } + } + + return move; +} + +/** + * A more advanced form of move_fromstring. Given also a board_t, will return + * a move_t for the move represented by str if it is 1) properly formatted, + * 2) valid, 3) legal. Otherwise returns 0. All appropriate flags will be set, + * so this is suitable for applymove. + * This code is not fast, as it will apply/undo the move from the board. Use + * it for checking the opponent's move, not the engine's move. + */ +move_t move_islegal(board_t *board, char *str, char **errmsg) +{ + move_t move; + square_t src, dest; + piece_t piece; + bitboard_t moves, clearsquares; + + /* Parse the string */ + move = move_fromstring(str); + src = MOV_SRC(move); + dest = MOV_DEST(move); + + /* First check: sanity; this also handles if move_fromstring failed */ + if (src == dest) + { + *errmsg = "!!! Motion is required for a move."; + return 0; + } + /* Does this piece belong to us */ + if (!(BB_SQUARE(src) & board->piecesofcolor[board->tomove])) + { + *errmsg = "!!! You don't have a piece there."; + return 0; + } + + /* Find our piece and where it can go */ + piece = board_pieceatsquare(board, src, NULL); + moves = board_attacksfrom(board, src, piece, board->tomove) & + (~(board->piecesofcolor[board->tomove])); /* can't capture own piece */ + move |= piece << MOV_INDEX_PIECE; /* set the piece-type flag */ + + /* of course, pawns and kings are special... */ + if (piece == PAWN) /* pushes and enpassants */ + { + /* can't make an attacking move unless it's a capture */ + moves &= board->piecesofcolor[OTHERCOLOR(board->tomove)]; + /* Trying to make an illegal promotion, or not promoting on an + * advance to the promotion rank */ + if ((!!(MOV_PROM(move))) ^ + (!!(ROW(dest) == HOMEROW(OTHERCOLOR(board->tomove))))) + { + if (!!(MOV_PROM(move))) { + *errmsg = "!!! Pawns don't promote like that."; + } else { + *errmsg = "!!! Promote into what? (N/B/R/Q)"; + } + return 0; + } + /* move is a regular capture */ + if (BB_SQUARE(dest) & moves) + { + move |= 1 << MOV_INDEX_CAPT; + move |= board_pieceatsquare(board, dest, NULL) << MOV_INDEX_CAPTPC; + return move_checksuicide(board, move, errmsg); + } + /* enpassant */ + if (board->ep && dest == board->ep) + { + move |= (0x1 << MOV_INDEX_EP) | + (0x1 << MOV_INDEX_CAPT) | + (PAWN << MOV_INDEX_CAPTPC); + return move_checksuicide(board, move, errmsg); + } + /* check for push */ + clearsquares = ~board->occupied; + /* is pawn free to move one square ahead? we don't need to set + * any special additional flags here */ + if (pawnmoves[board->tomove][src] & clearsquares) + { + /* Are we trying to move 1 square ahead? Note: relies + * on the fact that pawnmoves[][] has one bit set. */ + if (BB_SQUARE(dest) == pawnmoves[board->tomove][src]) + { + return move_checksuicide(board, move, errmsg); + } + /* 2-square push from 2nd rank */ + if (((board->tomove == WHITE) && + (pawnmoves[board->tomove][src+8] & clearsquares) && + (BB_SQUARE(dest) == pawnmoves[board->tomove][src+8])) || + ((board->tomove == BLACK) && + (pawnmoves[board->tomove][src-8] & clearsquares) && + (BB_SQUARE(dest) == pawnmoves[board->tomove][src-8]))) + { + return move_checksuicide(board, move, errmsg); + } + } + *errmsg = "!!! Pawns can't move like that."; + return 0; + } + /* not a pawn, trying to promote a different piece */ + else if (MOV_PROM(move)) + { + *errmsg = "!!! You can't promote non-pawns!"; + return 0; + } + /* note - for king moves, we don't need to apply the move to check if + * it puts the player in check; we use squareisattacked() directly */ + else if (piece == KING) + { + /* handle castling - queenside */ + if (board->castle[board->tomove][QUEENSIDE] && + (src == SQUARE(COL_E,HOMEROW(board->tomove))) && + (dest == SQUARE(COL_C,HOMEROW(board->tomove)))) /* "e1c1" or "e8c8" */ + { + /* check if special squares are blocked or attacked */ + if (castle_clearsquares[board->tomove][QUEENSIDE] & board->occupied) { + *errmsg = "!!! Castling squares are blocked."; + return 0; + } else if (board_squaresareattacked(board, castle_safesquares[board->tomove][QUEENSIDE], OTHERCOLOR(board->tomove))) { + *errmsg = "!!! Can't castle through check."; + return 0; + } + /* here, the castle is legal */ + move |= 0x1 << MOV_INDEX_CASTLE; + return move; + } + /* kingside */ + if (board->castle[board->tomove][KINGSIDE] && + (src == SQUARE(COL_E,HOMEROW(board->tomove))) && + (dest == SQUARE(COL_G,HOMEROW(board->tomove)))) /* "e1g1" or "e8g8" */ + { + /* check if special squares are blocked or attacked */ + if (castle_clearsquares[board->tomove][KINGSIDE] & board->occupied) { + *errmsg = "!!! Castling squares are blocked."; + return 0; + } else if (board_squaresareattacked(board, castle_safesquares[board->tomove][KINGSIDE], OTHERCOLOR(board->tomove))) { + *errmsg = "!!! Can't castle through check."; + return 0; + } + /* here, the castle is legal */ + move |= 0x1 << MOV_INDEX_CASTLE; + return move; + } + /* otherwise it must be a normal king move to be legal */ + /* we can make this move */ + if (BB_SQUARE(dest) & moves) + { + /* making a capture */ + if (BB_SQUARE(dest) & board->piecesofcolor[OTHERCOLOR(board->tomove)]) + { + move |= 1 << MOV_INDEX_CAPT; + move |= board_pieceatsquare(board, dest, NULL) << MOV_INDEX_CAPTPC; + } + if (board_squareisattacked(board, dest, OTHERCOLOR(board->tomove))) + { + *errmsg = "!!! Can't move king into check."; + return 0; + } + return move; + } + *errmsg = "!!! Kings can't move like that."; + return 0; + } + /* typical case piece - N B R Q */ + else + { + /* is this one of our legal moves? */ + if (BB_SQUARE(dest) & moves) + { + /* making a capture? */ + if (BB_SQUARE(dest) & board->piecesofcolor[OTHERCOLOR(board->tomove)]) + { + move |= 1 << MOV_INDEX_CAPT; + move |= board_pieceatsquare(board, dest, NULL) << MOV_INDEX_CAPTPC; + } + return move_checksuicide(board, move, errmsg); + } + *errmsg = + piece == QUEEN ? "!!! Queens can't move like that." : + piece == ROOK ? "!!! Rooks can't move like that." : + piece == BISHOP ? "!!! Bishops can't move like that." : + "!!! Knights can't move like that."; + return 0; + } +} + +/** + * Given a move on a given position (must be legal and suitably formatted for + * applymove), check if making this move would leave the player in check. + * Returns the move if it's good, 0 if not. + */ +static move_t move_checksuicide(board_t *board, move_t move, char **errmsg) +{ + board_applymove(board, move); + if (board_colorincheck(board, OTHERCOLOR(board->tomove))) + { + board_undomove(board, move); + *errmsg = "!!! That would put you in check."; + return 0; + } + board_undomove(board, move); + return move; +} + +/** + * Returns the string representation of a move in computer-friendly format + * (that is, "squarename[src]squarename[dest]promotionpiece"). Free the string + * when you're done with it. + */ +char *move_tostring(move_t m) +{ + char *string; + /* longest move in this format is a promotion, "a7a8Q" */ + string = malloc(6); + affirm_msg(string, "Couldn't allocate move string"); + string[0] = 0; + strcat(string, squarename[MOV_SRC(m)]); + strcat(string, squarename[MOV_DEST(m)]); + if (MOV_PROM(m)) + { + /* use WHITE as an index to get the uppercase */ + strcat(string, piecename[WHITE][MOV_PROMPC(m)]); + } + return string; +} +/**************************************************************************** + * book.c - simple interface for retrieving moves from a plaintext book + * copyright (C) 2008 Ben Blum + * ****************************************************************************/ + +#define BOOK_MOVE_LENGTH 4 + +// Must be sorted. +const char *book[] = { + "c2c4 c7c5 g1f3 b8c6", + "c2c4 c7c5 g1f3 g8f6 b1c3 b8c6", + "c2c4 c7c5 g1f3 g8f6 b1c3 e7e6 g2g3 b7b6 f1g2 c8b7 e1g1 f8e7", + "c2c4 c7c5 g1f3 g8f6 g2g3", + "c2c4 c7c6", + "c2c4 e7e5 b1c3 b8c6", + "c2c4 e7e5 b1c3 g8f6 g1f3 b8c6 g2g3", + "c2c4 e7e5 g2g3", + "c2c4 e7e6 b1c3 d7d5 d2d4 c7c6", + "c2c4 e7e6 b1c3 d7d5 d2d4 f8e7 g1f3 g8f6 c1f4 e8g8 e2e3", + "c2c4 e7e6 b1c3 d7d5 d2d4 f8e7 g1f3 g8f6 c1g5 e8g8 e2e3 h7h6", + "c2c4 e7e6 b1c3 d7d5 d2d4 f8e7 g1f3 g8f6 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "c2c4 e7e6 b1c3 d7d5 d2d4 g8f6 c1g5 f8e7 e2e3", + "c2c4 e7e6 b1c3 d7d5 d2d4 g8f6 c4d5 e6d5 c1g5", + "c2c4 e7e6 b1c3 d7d5 d2d4 g8f6 g1f3 b8d7", + "c2c4 e7e6 b1c3 d7d5 d2d4 g8f6 g1f3 c7c5", + "c2c4 e7e6 b1c3 d7d5 d2d4 g8f6 g1f3 c7c6 c1g5", + "c2c4 e7e6 b1c3 d7d5 d2d4 g8f6 g1f3 c7c6 e2e3 b8d7 d1c2 f8d6", + "c2c4 e7e6 b1c3 d7d5 d2d4 g8f6 g1f3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "c2c4 e7e6 b1c3 d7d5 d2d4 g8f6 g1f3 f8b4", + "c2c4 e7e6 b1c3 d7d5 d2d4 g8f6 g1f3 f8e7 c1f4 e8g8 e2e3", + "c2c4 e7e6 b1c3 d7d5 d2d4 g8f6 g1f3 f8e7 c1g5 e8g8 e2e3 h7h6", + "c2c4 e7e6 b1c3 d7d5 d2d4 g8f6 g1f3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "c2c4 e7e6 g1f3", + "c2c4 g8f6 b1c3 c7c5", + "c2c4 g8f6 b1c3 e7e5 g1f3 b8c6 g2g3", + "c2c4 g8f6 b1c3 e7e6 g1f3 d7d5 d2d4 b8d7", + "c2c4 g8f6 b1c3 e7e6 g1f3 d7d5 d2d4 c7c5", + "c2c4 g8f6 b1c3 e7e6 g1f3 d7d5 d2d4 c7c6 c1g5", + "c2c4 g8f6 b1c3 e7e6 g1f3 d7d5 d2d4 c7c6 e2e3 b8d7 d1c2 f8d6", + "c2c4 g8f6 b1c3 e7e6 g1f3 d7d5 d2d4 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "c2c4 g8f6 b1c3 e7e6 g1f3 d7d5 d2d4 f8b4", + "c2c4 g8f6 b1c3 e7e6 g1f3 d7d5 d2d4 f8e7 c1f4 e8g8 e2e3", + "c2c4 g8f6 b1c3 e7e6 g1f3 d7d5 d2d4 f8e7 c1g5 e8g8 e2e3 h7h6", + "c2c4 g8f6 b1c3 e7e6 g1f3 d7d5 d2d4 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "c2c4 g8f6 b1c3 g7g6", + "c2c4 g8f6 g1f3 b7b6 g2g3", + "c2c4 g8f6 g1f3 c7c5 b1c3 b8c6", + "c2c4 g8f6 g1f3 c7c5 b1c3 e7e6 g2g3 b7b6 f1g2 c8b7 e1g1 f8e7", + "c2c4 g8f6 g1f3 c7c5 g2g3", + "c2c4 g8f6 g1f3 e7e6 b1c3 d7d5 d2d4 b8d7", + "c2c4 g8f6 g1f3 e7e6 b1c3 d7d5 d2d4 c7c5", + "c2c4 g8f6 g1f3 e7e6 b1c3 d7d5 d2d4 c7c6 c1g5", + "c2c4 g8f6 g1f3 e7e6 b1c3 d7d5 d2d4 c7c6 e2e3 b8d7 d1c2 f8d6", + "c2c4 g8f6 g1f3 e7e6 b1c3 d7d5 d2d4 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "c2c4 g8f6 g1f3 e7e6 b1c3 d7d5 d2d4 f8b4", + "c2c4 g8f6 g1f3 e7e6 b1c3 d7d5 d2d4 f8e7 c1f4 e8g8 e2e3", + "c2c4 g8f6 g1f3 e7e6 b1c3 d7d5 d2d4 f8e7 c1g5 e8g8 e2e3 h7h6", + "c2c4 g8f6 g1f3 e7e6 b1c3 d7d5 d2d4 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "c2c4 g8f6 g1f3 e7e6 g2g3 d7d5 f1g2 f8e7", + "c2c4 g8f6 g1f3 g7g6 b1c3 f8g7 e2e4", + "c2c4 g8f6 g1f3 g7g6 g2g3 f8g7 f1g2 e8g8", + "d2d4 d7d5 c2c4 c7c6 b1c3 g8f6 e2e3", + "d2d4 d7d5 c2c4 c7c6 b1c3 g8f6 g1f3 d5c4 a2a4 c8f5 e2e3 e7e6 f1c4", + "d2d4 d7d5 c2c4 c7c6 b1c3 g8f6 g1f3 e7e6 c1g5", + "d2d4 d7d5 c2c4 c7c6 b1c3 g8f6 g1f3 e7e6 e2e3 b8d7 d1c2 f8d6", + "d2d4 d7d5 c2c4 c7c6 b1c3 g8f6 g1f3 e7e6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 d7d5 c2c4 c7c6 g1f3 g8f6 b1c3 d5c4 a2a4 c8f5 e2e3 e7e6 f1c4", + "d2d4 d7d5 c2c4 c7c6 g1f3 g8f6 b1c3 e7e6 c1g5", + "d2d4 d7d5 c2c4 c7c6 g1f3 g8f6 b1c3 e7e6 e2e3 b8d7 d1c2 f8d6", + "d2d4 d7d5 c2c4 c7c6 g1f3 g8f6 b1c3 e7e6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 d7d5 c2c4 c7c6 g1f3 g8f6 e2e3", + "d2d4 d7d5 c2c4 d5c4 g1f3 e7e6 e2e3 g8f6", + "d2d4 d7d5 c2c4 d5c4 g1f3 g8f6 e2e3 e7e6 f1c4 c7c5 e1g1 a7a6", + "d2d4 d7d5 c2c4 e7e6 b1c3 c7c6", + "d2d4 d7d5 c2c4 e7e6 b1c3 f8e7 g1f3 g8f6 c1f4 e8g8 e2e3", + "d2d4 d7d5 c2c4 e7e6 b1c3 f8e7 g1f3 g8f6 c1g5 e8g8 e2e3 h7h6", + "d2d4 d7d5 c2c4 e7e6 b1c3 f8e7 g1f3 g8f6 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "d2d4 d7d5 c2c4 e7e6 b1c3 g8f6 c1g5 f8e7 e2e3", + "d2d4 d7d5 c2c4 e7e6 b1c3 g8f6 c4d5 e6d5 c1g5", + "d2d4 d7d5 c2c4 e7e6 b1c3 g8f6 g1f3 b8d7", + "d2d4 d7d5 c2c4 e7e6 b1c3 g8f6 g1f3 c7c5", + "d2d4 d7d5 c2c4 e7e6 b1c3 g8f6 g1f3 c7c6 c1g5", + "d2d4 d7d5 c2c4 e7e6 b1c3 g8f6 g1f3 c7c6 e2e3 b8d7 d1c2 f8d6", + "d2d4 d7d5 c2c4 e7e6 b1c3 g8f6 g1f3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 d7d5 c2c4 e7e6 b1c3 g8f6 g1f3 f8b4", + "d2d4 d7d5 c2c4 e7e6 b1c3 g8f6 g1f3 f8e7 c1f4 e8g8 e2e3", + "d2d4 d7d5 c2c4 e7e6 b1c3 g8f6 g1f3 f8e7 c1g5 e8g8 e2e3 h7h6", + "d2d4 d7d5 c2c4 e7e6 b1c3 g8f6 g1f3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "d2d4 d7d5 c2c4 e7e6 g1f3 g8f6 b1c3 b8d7", + "d2d4 d7d5 c2c4 e7e6 g1f3 g8f6 b1c3 c7c5", + "d2d4 d7d5 c2c4 e7e6 g1f3 g8f6 b1c3 c7c6 c1g5", + "d2d4 d7d5 c2c4 e7e6 g1f3 g8f6 b1c3 c7c6 e2e3 b8d7 d1c2 f8d6", + "d2d4 d7d5 c2c4 e7e6 g1f3 g8f6 b1c3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 d7d5 c2c4 e7e6 g1f3 g8f6 b1c3 f8b4", + "d2d4 d7d5 c2c4 e7e6 g1f3 g8f6 b1c3 f8e7 c1f4 e8g8 e2e3", + "d2d4 d7d5 c2c4 e7e6 g1f3 g8f6 b1c3 f8e7 c1g5 e8g8 e2e3 h7h6", + "d2d4 d7d5 c2c4 e7e6 g1f3 g8f6 b1c3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "d2d4 d7d5 c2c4 e7e6 g1f3 g8f6 c1g5", + "d2d4 d7d5 c2c4 e7e6 g1f3 g8f6 g2g3", + "d2d4 d7d5 g1f3 e7e6 c2c4 g8f6 b1c3 b8d7", + "d2d4 d7d5 g1f3 e7e6 c2c4 g8f6 b1c3 c7c5", + "d2d4 d7d5 g1f3 e7e6 c2c4 g8f6 b1c3 c7c6 c1g5", + "d2d4 d7d5 g1f3 e7e6 c2c4 g8f6 b1c3 c7c6 e2e3 b8d7 d1c2 f8d6", + "d2d4 d7d5 g1f3 e7e6 c2c4 g8f6 b1c3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 d7d5 g1f3 e7e6 c2c4 g8f6 b1c3 f8b4", + "d2d4 d7d5 g1f3 e7e6 c2c4 g8f6 b1c3 f8e7 c1f4 e8g8 e2e3", + "d2d4 d7d5 g1f3 e7e6 c2c4 g8f6 b1c3 f8e7 c1g5 e8g8 e2e3 h7h6", + "d2d4 d7d5 g1f3 e7e6 c2c4 g8f6 b1c3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "d2d4 d7d5 g1f3 e7e6 c2c4 g8f6 c1g5", + "d2d4 d7d5 g1f3 e7e6 c2c4 g8f6 g2g3", + "d2d4 d7d5 g1f3 g8f6 c2c4 c7c6 b1c3 d5c4 a2a4 c8f5 e2e3 e7e6 f1c4", + "d2d4 d7d5 g1f3 g8f6 c2c4 c7c6 b1c3 e7e6 c1g5", + "d2d4 d7d5 g1f3 g8f6 c2c4 c7c6 b1c3 e7e6 e2e3 b8d7 d1c2 f8d6", + "d2d4 d7d5 g1f3 g8f6 c2c4 c7c6 b1c3 e7e6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 d7d5 g1f3 g8f6 c2c4 c7c6 e2e3", + "d2d4 d7d5 g1f3 g8f6 c2c4 d5c4 e2e3 e7e6 f1c4 c7c5 e1g1 a7a6", + "d2d4 d7d5 g1f3 g8f6 c2c4 e7e6 b1c3 b8d7", + "d2d4 d7d5 g1f3 g8f6 c2c4 e7e6 b1c3 c7c5", + "d2d4 d7d5 g1f3 g8f6 c2c4 e7e6 b1c3 c7c6 c1g5", + "d2d4 d7d5 g1f3 g8f6 c2c4 e7e6 b1c3 c7c6 e2e3 b8d7 d1c2 f8d6", + "d2d4 d7d5 g1f3 g8f6 c2c4 e7e6 b1c3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 d7d5 g1f3 g8f6 c2c4 e7e6 b1c3 f8b4", + "d2d4 d7d5 g1f3 g8f6 c2c4 e7e6 b1c3 f8e7 c1f4 e8g8 e2e3", + "d2d4 d7d5 g1f3 g8f6 c2c4 e7e6 b1c3 f8e7 c1g5 e8g8 e2e3 h7h6", + "d2d4 d7d5 g1f3 g8f6 c2c4 e7e6 b1c3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "d2d4 d7d5 g1f3 g8f6 c2c4 e7e6 c1g5", + "d2d4 d7d5 g1f3 g8f6 c2c4 e7e6 g2g3", + "d2d4 d7d6 e2e4 g7g6", + "d2d4 d7d6 e2e4 g8f6 b1c3 g7g6 f2f4 f8g7 g1f3", + "d2d4 e7e6 c2c4 b7b6 g1f3", + "d2d4 e7e6 c2c4 g8f6 b1c3 d7d5 c1g5 f8e7 e2e3", + "d2d4 e7e6 c2c4 g8f6 b1c3 d7d5 c4d5 e6d5 c1g5", + "d2d4 e7e6 c2c4 g8f6 b1c3 d7d5 g1f3 b8d7", + "d2d4 e7e6 c2c4 g8f6 b1c3 d7d5 g1f3 c7c5", + "d2d4 e7e6 c2c4 g8f6 b1c3 d7d5 g1f3 c7c6 c1g5", + "d2d4 e7e6 c2c4 g8f6 b1c3 d7d5 g1f3 c7c6 e2e3 b8d7 d1c2 f8d6", + "d2d4 e7e6 c2c4 g8f6 b1c3 d7d5 g1f3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 e7e6 c2c4 g8f6 b1c3 d7d5 g1f3 f8b4", + "d2d4 e7e6 c2c4 g8f6 b1c3 d7d5 g1f3 f8e7 c1f4 e8g8 e2e3", + "d2d4 e7e6 c2c4 g8f6 b1c3 d7d5 g1f3 f8e7 c1g5 e8g8 e2e3 h7h6", + "d2d4 e7e6 c2c4 g8f6 b1c3 d7d5 g1f3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "d2d4 e7e6 c2c4 g8f6 b1c3 f8b4 d1c2 e8g8", + "d2d4 e7e6 c2c4 g8f6 b1c3 f8b4 e2e3 b7b6", + "d2d4 e7e6 c2c4 g8f6 b1c3 f8b4 e2e3 c7c5 f1d3", + "d2d4 e7e6 c2c4 g8f6 b1c3 f8b4 e2e3 e8g8 f1d3 d7d5 g1f3", + "d2d4 e7e6 c2c4 g8f6 b1c3 f8b4 g1f3", + "d2d4 e7e6 c2c4 g8f6 c1g5 f8b4", + "d2d4 e7e6 c2c4 g8f6 c1g5 h7h6", + "d2d4 e7e6 c2c4 g8f6 g1f3 b7b6 a2a3 c8b7 b1c3 d7d5 c4d5 f6d5", + "d2d4 e7e6 c2c4 g8f6 g1f3 b7b6 b1c3 c8b7 a2a3 d7d5 c4d5 f6d5", + "d2d4 e7e6 c2c4 g8f6 g1f3 b7b6 b1c3 f8b4", + "d2d4 e7e6 c2c4 g8f6 g1f3 b7b6 g2g3 c8a6 b2b3 f8b4 c1d2 b4e7", + "d2d4 e7e6 c2c4 g8f6 g1f3 b7b6 g2g3 c8b7 f1g2 f8e7 e1g1 e8g8 b1c3 f6e4 d1c2 e4c3 c2c3", + "d2d4 e7e6 c2c4 g8f6 g1f3 c7c5 d4d5 e6d5 c4d5 d7d6 b1c3 g7g6", + "d2d4 e7e6 c2c4 g8f6 g1f3 d7d5 b1c3 b8d7", + "d2d4 e7e6 c2c4 g8f6 g1f3 d7d5 b1c3 c7c5", + "d2d4 e7e6 c2c4 g8f6 g1f3 d7d5 b1c3 c7c6 c1g5", + "d2d4 e7e6 c2c4 g8f6 g1f3 d7d5 b1c3 c7c6 e2e3 b8d7 d1c2 f8d6", + "d2d4 e7e6 c2c4 g8f6 g1f3 d7d5 b1c3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 e7e6 c2c4 g8f6 g1f3 d7d5 b1c3 f8b4", + "d2d4 e7e6 c2c4 g8f6 g1f3 d7d5 b1c3 f8e7 c1f4 e8g8 e2e3", + "d2d4 e7e6 c2c4 g8f6 g1f3 d7d5 b1c3 f8e7 c1g5 e8g8 e2e3 h7h6", + "d2d4 e7e6 c2c4 g8f6 g1f3 d7d5 b1c3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "d2d4 e7e6 c2c4 g8f6 g1f3 d7d5 c1g5", + "d2d4 e7e6 c2c4 g8f6 g1f3 d7d5 g2g3", + "d2d4 e7e6 c2c4 g8f6 g1f3 f8b4 b1d2", + "d2d4 e7e6 c2c4 g8f6 g1f3 f8b4 c1d2", + "d2d4 e7e6 c2c4 g8f6 g2g3 d7d5 f1g2", + "d2d4 e7e6 e2e4 d7d5 b1c3 f8b4 e4e5 c7c5 a2a3 b4c3", + "d2d4 e7e6 e2e4 d7d5 b1d2 c7c5 g1f3", + "d2d4 e7e6 e2e4 d7d5 b1d2 g8f6 e4e5 f6d7 f1d3 c7c5 c2c3 b8c6 g1e2 ", + "d2d4 g8f6 c1g5 f6e4 g5f4 c7c5 f2f3 d8a5 c2c3 e4f6 d4d5 a5b6", + "d2d4 g8f6 c2c4 c7c5 d4d5 b7b5 c4b5 a7a6", + "d2d4 g8f6 c2c4 c7c5 d4d5 e7e6 b1c3 e6d5 c4d5 d7d6", + "d2d4 g8f6 c2c4 d7d6 b1c3", + "d2d4 g8f6 c2c4 e7e6 b1c3 d7d5 c1g5 f8e7 e2e3", + "d2d4 g8f6 c2c4 e7e6 b1c3 d7d5 c4d5 e6d5 c1g5", + "d2d4 g8f6 c2c4 e7e6 b1c3 d7d5 g1f3 b8d7", + "d2d4 g8f6 c2c4 e7e6 b1c3 d7d5 g1f3 c7c5", + "d2d4 g8f6 c2c4 e7e6 b1c3 d7d5 g1f3 c7c6 c1g5", + "d2d4 g8f6 c2c4 e7e6 b1c3 d7d5 g1f3 c7c6 e2e3 b8d7 d1c2 f8d6", + "d2d4 g8f6 c2c4 e7e6 b1c3 d7d5 g1f3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 g8f6 c2c4 e7e6 b1c3 d7d5 g1f3 f8b4", + "d2d4 g8f6 c2c4 e7e6 b1c3 d7d5 g1f3 f8e7 c1f4 e8g8 e2e3", + "d2d4 g8f6 c2c4 e7e6 b1c3 d7d5 g1f3 f8e7 c1g5 e8g8 e2e3 h7h6", + "d2d4 g8f6 c2c4 e7e6 b1c3 d7d5 g1f3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "d2d4 g8f6 c2c4 e7e6 b1c3 f8b4 d1c2 e8g8", + "d2d4 g8f6 c2c4 e7e6 b1c3 f8b4 e2e3 b7b6", + "d2d4 g8f6 c2c4 e7e6 b1c3 f8b4 e2e3 c7c5 f1d3", + "d2d4 g8f6 c2c4 e7e6 b1c3 f8b4 e2e3 e8g8 f1d3 d7d5 g1f3", + "d2d4 g8f6 c2c4 e7e6 b1c3 f8b4 g1f3", + "d2d4 g8f6 c2c4 e7e6 g1f3 b7b6 a2a3 c8b7 b1c3 d7d5 c4d5 f6d5", + "d2d4 g8f6 c2c4 e7e6 g1f3 b7b6 b1c3 c8b7 a2a3 d7d5 c4d5 f6d5", + "d2d4 g8f6 c2c4 e7e6 g1f3 b7b6 b1c3 f8b4", + "d2d4 g8f6 c2c4 e7e6 g1f3 b7b6 g2g3 c8a6 b2b3 f8b4 c1d2 b4e7", + "d2d4 g8f6 c2c4 e7e6 g1f3 b7b6 g2g3 c8b7 f1g2 f8e7 e1g1 e8g8 b1c3 f6e4 d1c2 e4c3 c2c3", + "d2d4 g8f6 c2c4 e7e6 g1f3 c7c5 d4d5 e6d5 c4d5 d7d6 b1c3 g7g6", + "d2d4 g8f6 c2c4 e7e6 g1f3 d7d5 b1c3 b8d7", + "d2d4 g8f6 c2c4 e7e6 g1f3 d7d5 b1c3 c7c5", + "d2d4 g8f6 c2c4 e7e6 g1f3 d7d5 b1c3 c7c6 c1g5", + "d2d4 g8f6 c2c4 e7e6 g1f3 d7d5 b1c3 c7c6 e2e3 b8d7 d1c2 f8d6", + "d2d4 g8f6 c2c4 e7e6 g1f3 d7d5 b1c3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 g8f6 c2c4 e7e6 g1f3 d7d5 b1c3 f8b4", + "d2d4 g8f6 c2c4 e7e6 g1f3 d7d5 b1c3 f8e7 c1f4 e8g8 e2e3", + "d2d4 g8f6 c2c4 e7e6 g1f3 d7d5 b1c3 f8e7 c1g5 e8g8 e2e3 h7h6", + "d2d4 g8f6 c2c4 e7e6 g1f3 d7d5 b1c3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "d2d4 g8f6 c2c4 e7e6 g1f3 d7d5 c1g5", + "d2d4 g8f6 c2c4 e7e6 g1f3 d7d5 g2g3", + "d2d4 g8f6 c2c4 e7e6 g1f3 f8b4 b1d2", + "d2d4 g8f6 c2c4 e7e6 g1f3 f8b4 c1d2", + "d2d4 g8f6 c2c4 e7e6 g2g3 d7d5 f1g2", + "d2d4 g8f6 c2c4 g7g6 b1c3 d7d5 c4d5 f6d5 e2e4 d5c3 b2c3 f8g7 f1c4", + "d2d4 g8f6 c2c4 g7g6 b1c3 d7d5 g1f3 f8g7 d1b3 d5c4 b3c4", + "d2d4 g8f6 c2c4 g7g6 b1c3 f8g7 e2e4 d7d6 f1e2 e8g8 c1g5", + "d2d4 g8f6 c2c4 g7g6 b1c3 f8g7 e2e4 d7d6 f1e2 e8g8 g1f3 e7e5 e1g1 b8c6 d4d5 c6e7 f3e1 f6d7", + "d2d4 g8f6 c2c4 g7g6 b1c3 f8g7 e2e4 d7d6 f2f3 e8g8 c1e3", + "d2d4 g8f6 c2c4 g7g6 b1c3 f8g7 e2e4 d7d6 g1f3 e8g8 f1e2 e7e5 e1g1 b8c6 d4d5 c6e7 f3e1 f6d7", + "d2d4 g8f6 c2c4 g7g6 g1f3 f8g7 b1c3 e8g8 e2e4 d7d6 f1e2 e7e5 e1g1 b8c6 d4d5 c6e7 f3e1 f6d7", + "d2d4 g8f6 c2c4 g7g6 g1f3 f8g7 g2g3 e8g8 f1g2 d7d6 e1g1", + "d2d4 g8f6 c2c4 g7g6 g2g3 f8g7 f1g2 e8g8", + "d2d4 g8f6 g1f3 c7c5", + "d2d4 g8f6 g1f3 d7d5 c2c4 c7c6 b1c3 d5c4 a2a4 c8f5 e2e3 e7e6 f1c4", + "d2d4 g8f6 g1f3 d7d5 c2c4 c7c6 b1c3 e7e6 c1g5", + "d2d4 g8f6 g1f3 d7d5 c2c4 c7c6 b1c3 e7e6 e2e3 b8d7 d1c2 f8d6", + "d2d4 g8f6 g1f3 d7d5 c2c4 c7c6 b1c3 e7e6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 g8f6 g1f3 d7d5 c2c4 c7c6 e2e3", + "d2d4 g8f6 g1f3 d7d5 c2c4 d5c4 e2e3 e7e6 f1c4 c7c5 e1g1 a7a6", + "d2d4 g8f6 g1f3 d7d5 c2c4 e7e6 b1c3 b8d7", + "d2d4 g8f6 g1f3 d7d5 c2c4 e7e6 b1c3 c7c5", + "d2d4 g8f6 g1f3 d7d5 c2c4 e7e6 b1c3 c7c6 c1g5", + "d2d4 g8f6 g1f3 d7d5 c2c4 e7e6 b1c3 c7c6 e2e3 b8d7 d1c2 f8d6", + "d2d4 g8f6 g1f3 d7d5 c2c4 e7e6 b1c3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 g8f6 g1f3 d7d5 c2c4 e7e6 b1c3 f8b4", + "d2d4 g8f6 g1f3 d7d5 c2c4 e7e6 b1c3 f8e7 c1f4 e8g8 e2e3", + "d2d4 g8f6 g1f3 d7d5 c2c4 e7e6 b1c3 f8e7 c1g5 e8g8 e2e3 h7h6", + "d2d4 g8f6 g1f3 d7d5 c2c4 e7e6 b1c3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "d2d4 g8f6 g1f3 d7d5 c2c4 e7e6 c1g5", + "d2d4 g8f6 g1f3 d7d5 c2c4 e7e6 g2g3", + "d2d4 g8f6 g1f3 e7e6 c1g5", + "d2d4 g8f6 g1f3 e7e6 c2c4 b7b6 a2a3 c8b7 b1c3 d7d5 c4d5 f6d5", + "d2d4 g8f6 g1f3 e7e6 c2c4 b7b6 b1c3 c8b7 a2a3 d7d5 c4d5 f6d5", + "d2d4 g8f6 g1f3 e7e6 c2c4 b7b6 b1c3 f8b4", + "d2d4 g8f6 g1f3 e7e6 c2c4 b7b6 g2g3 c8a6 b2b3 f8b4 c1d2 b4e7", + "d2d4 g8f6 g1f3 e7e6 c2c4 b7b6 g2g3 c8b7 f1g2 f8e7 e1g1 e8g8 b1c3 f6e4 d1c2 e4c3 c2c3", + "d2d4 g8f6 g1f3 e7e6 c2c4 c7c5 d4d5 e6d5 c4d5 d7d6 b1c3 g7g6", + "d2d4 g8f6 g1f3 e7e6 c2c4 d7d5 b1c3 b8d7", + "d2d4 g8f6 g1f3 e7e6 c2c4 d7d5 b1c3 c7c5", + "d2d4 g8f6 g1f3 e7e6 c2c4 d7d5 b1c3 c7c6 c1g5", + "d2d4 g8f6 g1f3 e7e6 c2c4 d7d5 b1c3 c7c6 e2e3 b8d7 d1c2 f8d6", + "d2d4 g8f6 g1f3 e7e6 c2c4 d7d5 b1c3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 g8f6 g1f3 e7e6 c2c4 d7d5 b1c3 f8b4", + "d2d4 g8f6 g1f3 e7e6 c2c4 d7d5 b1c3 f8e7 c1f4 e8g8 e2e3", + "d2d4 g8f6 g1f3 e7e6 c2c4 d7d5 b1c3 f8e7 c1g5 e8g8 e2e3 h7h6", + "d2d4 g8f6 g1f3 e7e6 c2c4 d7d5 b1c3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "d2d4 g8f6 g1f3 e7e6 c2c4 d7d5 c1g5", + "d2d4 g8f6 g1f3 e7e6 c2c4 d7d5 g2g3", + "d2d4 g8f6 g1f3 e7e6 c2c4 f8b4 b1d2", + "d2d4 g8f6 g1f3 e7e6 c2c4 f8b4 c1d2", + "d2d4 g8f6 g1f3 e7e6 g2g3", + "d2d4 g8f6 g1f3 g7g6 c1g5", + "d2d4 g8f6 g1f3 g7g6 c2c4 f8g7 b1c3 e8g8 e2e4 d7d6 f1e2 e7e5 e1g1 b8c6 d4d5 c6e7 f3e1 f6d7", + "d2d4 g8f6 g1f3 g7g6 c2c4 f8g7 g2g3 e8g8 f1g2 d7d6 e1g1", + "d2d4 g8f6 g1f3 g7g6 g2g3 f8g7 f1g2 e8g8", + "e2e4 c7c5 b1c3 b8c6 g2g3 g7g6 f1g2 f8g7", + "e2e4 c7c5 c2c3 d7d6 g1f3 g8f6", + "e2e4 c7c5 c2c3 g8f6 e4e5 f6d5 d2d4 c5d4 g1f3 ", + "e2e4 c7c5 c2c3 g8f6 e4e5 f6d5 g1f3", + "e2e4 c7c5 d2d3 g8f6", + "e2e4 c7c5 g1f3 b8c6 d2d4 c5d4 f3d4 e7e6 b1c3 a7a6", + "e2e4 c7c5 g1f3 b8c6 d2d4 c5d4 f3d4 e7e6 b1c3 d8c7", + "e2e4 c7c5 g1f3 b8c6 d2d4 c5d4 f3d4 g7g6 b1c3 f8g7 c1e3 g8f6 f1c4", + "e2e4 c7c5 g1f3 b8c6 d2d4 c5d4 f3d4 g7g6 c2c4 f8g7 f1d3 g8f6 b1c3 ", + "e2e4 c7c5 g1f3 b8c6 d2d4 c5d4 f3d4 g8f6 b1c3 d7d6 c1g5 e7e6 d1d2 a7a6 e1c1 h7h6", + "e2e4 c7c5 g1f3 b8c6 d2d4 c5d4 f3d4 g8f6 b1c3 d7d6 c1g5 e7e6 d1d2 f8e7 e1c1 e8g8", + "e2e4 c7c5 g1f3 b8c6 d2d4 c5d4 f3d4 g8f6 b1c3 d7d6 f1c4", + "e2e4 c7c5 g1f3 b8c6 d2d4 c5d4 f3d4 g8f6 b1c3 e7e5 d4b5 d7d6", + "e2e4 c7c5 g1f3 b8c6 f1b5", + "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4 f3d4 g8f6 b1c3 a7a6 c1e3", + "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4 f3d4 g8f6 b1c3 a7a6 c1g5 e7e6 f2f4", + "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4 f3d4 g8f6 b1c3 a7a6 f1e2 e7e5 d4b3 f8e7", + "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4 f3d4 g8f6 b1c3 a7a6 f2f4", + "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4 f3d4 g8f6 b1c3 b8c6 c1g5 e7e6 d1d2 a7a6 e1c1 h7h6", + "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4 f3d4 g8f6 b1c3 b8c6 c1g5 e7e6 d1d2 f8e7 e1c1 e8g8", + "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4 f3d4 g8f6 b1c3 b8c6 f1c4", + "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4 f3d4 g8f6 b1c3 e7e6 f1e2", + "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4 f3d4 g8f6 b1c3 e7e6 g2g4", + "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4 f3d4 g8f6 b1c3 g7g6 c1e3 f8g7 f2f3", + "e2e4 c7c5 g1f3 d7d6 f1b5 b8d7", + "e2e4 c7c5 g1f3 d7d6 f1b5 c8d7 b5d7", + "e2e4 c7c5 g1f3 e7e6 b1c3", + "e2e4 c7c5 g1f3 e7e6 d2d4 c5d4 f3d4 a7a6 f1d3", + "e2e4 c7c5 g1f3 e7e6 d2d4 c5d4 f3d4 b8c6 b1c3 a7a6", + "e2e4 c7c5 g1f3 e7e6 d2d4 c5d4 f3d4 b8c6 b1c3 d8c7", + "e2e4 c7c5 g1f3 e7e6 d2d4 c5d4 f3d4 g8f6 b1c3 d7d6 f1e2", + "e2e4 c7c5 g1f3 e7e6 d2d4 c5d4 f3d4 g8f6 b1c3 d7d6 g2g4", + "e2e4 c7c6 c2c4 d7d5", + "e2e4 c7c6 d2d4 d7d5 b1c3 d5e4 c3e4 b8d7", + "e2e4 c7c6 d2d4 d7d5 b1c3 d5e4 c3e4 c8f5 e4g3 f5g6 h2h4 h7h6", + "e2e4 c7c6 d2d4 d7d5 b1d2 d5e4 d2e4 b8d7", + "e2e4 c7c6 d2d4 d7d5 b1d2 d5e4 d2e4 c8f5 e4g3 f5g6 h2h4 h7h6", + "e2e4 c7c6 d2d4 d7d5 e4d5 c6d5 c2c4 g8f6 b1c3 e7e6 g1f3", + "e2e4 c7c6 d2d4 d7d5 e4e5 c8f5", + "e2e4 c7c6 b1c3 d7d5 d2d4 d5e4 c3e4 c8f5 e4g3 f5g6 h2h4 h7h6", + "e2e4 c7c6 b1c3 d7d5 g1f3 c8g4 h2h3 g4f3 d1f3 e7e6", + "e2e4 c7c6 b1c3 d7d5 g1f3 d5e4 c3e4 g8f6", + "e2e4 c7c6 g1f3 d7d5 b1c3", + "e2e4 d7d6 d2d4 g7g6", + "e2e4 d7d6 d2d4 g8f6 b1c3 g7g6 f2f4 f8g7 g1f3", + "e2e4 e7e5 b1c3 g8f6 g1f3 b8c6", + "e2e4 e7e5 g1f3 b8c6 b1c3 g8f6 f1b5", + "e2e4 e7e5 g1f3 b8c6 d2d4 e5d4 f3d4", + "e2e4 e7e5 g1f3 b8c6 f1b5 a7a6 b5a4 d7d6", + "e2e4 e7e5 g1f3 b8c6 f1b5 a7a6 b5a4 g8f6 e1g1 f6e4 d2d4 b7b5 a4b3 d7d5 d4e5 c8e6 c2c3", + "e2e4 e7e5 g1f3 b8c6 f1b5 a7a6 b5a4 g8f6 e1g1 f8e7 f1e1 b7b5 a4b3 d7d6 c2c3 e8g8 h2h3 c6a5 b3c2 c7c5 d2d4 d8c7 b1d2", + "e2e4 e7e5 g1f3 b8c6 f1b5 a7a6 b5a4 g8f6 e1g1 f8e7 f1e1 b7b5 a4b3 d7d6 c2c3 e8g8 h2h3 c6b8 d2d4 b8d7", + "e2e4 e7e5 g1f3 b8c6 f1b5 a7a6 b5a4 g8f6 e1g1 f8e7 f1e1 b7b5 a4b3 d7d6 c2c3 e8g8 h2h3 c8b7 d2d4 f8e8", + "e2e4 e7e5 g1f3 b8c6 f1b5 a7a6 b5a4 g8f6 e1g1 f8e7 f1e1 b7b5 a4b3 e8g8 c2c3 d7d6 h2h3 c6a5 b3c2 c7c5 d2d4 d8c7 b1d2", + "e2e4 e7e5 g1f3 b8c6 f1b5 a7a6 b5a4 g8f6 e1g1 f8e7 f1e1 b7b5 a4b3 e8g8 c2c3 d7d6 h2h3 c6b8 d2d4 b8d7", + "e2e4 e7e5 g1f3 b8c6 f1b5 a7a6 b5a4 g8f6 e1g1 f8e7 f1e1 b7b5 a4b3 e8g8 c2c3 d7d6 h2h3 c8b7 d2d4 f8e8", + "e2e4 e7e5 g1f3 b8c6 f1b5 a7a6 b5c6 d7c6 e1g1", + "e2e4 e7e5 g1f3 b8c6 f1b5 g8f6 e1g1", + "e2e4 e7e5 g1f3 b8c6 f1c4 f8c5", + "e2e4 e7e5 g1f3 b8c6 f1c4 g8f6", + "e2e4 e7e5 g1f3 g8f6 f3e5 d7d6 e5f3 f6e4 d2d4", + "e2e4 e7e6 d2d4 d7d5 b1c3 f8b4 e4e5 c7c5 a2a3 b4c3 b2c3 g8e7", + "e2e4 e7e6 d2d4 d7d5 b1c3 g8f6 c1g5", + "e2e4 e7e6 d2d4 d7d5 b1d2 c7c5 e4d5 e6d5", + "e2e4 e7e6 d2d4 d7d5 b1d2 c7c5 g1f3", + "e2e4 e7e6 d2d4 d7d5 b1d2 g8f6 e4e5", + "e2e4 e7e6 d2d4 d7d5 e4e5 c7c5 c2c3 b8c6 g1f3 d8b6 a2a3 ", + "e2e4 e7e6 d2d4 d7d5 e4e5 c7c5 c2c3 d8b6 g1f3 b8c6 a2a3", + "e2e4 g7g6 d2d4 f8g7 b1c3 c7c6 g1f3", + "e2e4 g7g6 d2d4 f8g7 b1c3 d7d6 c1e3", + "e2e4 g7g6 d2d4 f8g7 b1c3 d7d6 g1f3", + "e2e4 g8f6 e4e5 f6d5 c2c4 d5b6 d2d4 d7d6 e5d6 e7d6", + "e2e4 g8f6 e4e5 f6d5 d2d4 d7d6 g1f3", + "g1f3 c7c5 c2c4 b8c6", + "g1f3 c7c5 c2c4 g8f6 b1c3 b8c6", + "g1f3 c7c5 c2c4 g8f6 b1c3 e7e6 g2g3 b7b6 f1g2 c8b7 e1g1 f8e7", + "g1f3 c7c5 c2c4 g8f6 g2g3", + "g1f3 d7d5 d2d4 g8f6 c2c4 c7c6 b1c3 d5c4 a2a4 c8f5 e2e3 e7e6 f1c4", + "g1f3 d7d5 d2d4 g8f6 c2c4 c7c6 b1c3 e7e6 c1g5", + "g1f3 d7d5 d2d4 g8f6 c2c4 c7c6 b1c3 e7e6 e2e3 b8d7 d1c2 f8d6", + "g1f3 d7d5 d2d4 g8f6 c2c4 c7c6 b1c3 e7e6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "g1f3 d7d5 d2d4 g8f6 c2c4 c7c6 e2e3", + "g1f3 d7d5 d2d4 g8f6 c2c4 d5c4 e2e3 e7e6 f1c4 c7c5 e1g1 a7a6", + "g1f3 d7d5 d2d4 g8f6 c2c4 e7e6 b1c3 b8d7", + "g1f3 d7d5 d2d4 g8f6 c2c4 e7e6 b1c3 c7c5", + "g1f3 d7d5 d2d4 g8f6 c2c4 e7e6 b1c3 c7c6 c1g5", + "g1f3 d7d5 d2d4 g8f6 c2c4 e7e6 b1c3 c7c6 e2e3 b8d7 d1c2 f8d6", + "g1f3 d7d5 d2d4 g8f6 c2c4 e7e6 b1c3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "g1f3 d7d5 d2d4 g8f6 c2c4 e7e6 b1c3 f8b4", + "g1f3 d7d5 d2d4 g8f6 c2c4 e7e6 b1c3 f8e7 c1f4 e8g8 e2e3", + "g1f3 d7d5 d2d4 g8f6 c2c4 e7e6 b1c3 f8e7 c1g5 e8g8 e2e3 h7h6", + "g1f3 d7d5 d2d4 g8f6 c2c4 e7e6 b1c3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "g1f3 d7d5 d2d4 g8f6 c2c4 e7e6 c1g5", + "g1f3 d7d5 d2d4 g8f6 c2c4 e7e6 g2g3", + "g1f3 d7d5 g2g3", + "g1f3 g8f6 c2c4 b7b6 g2g3", + "g1f3 g8f6 c2c4 c7c5 b1c3 b8c6", + "g1f3 g8f6 c2c4 c7c5 b1c3 e7e6 g2g3 b7b6 f1g2 c8b7 e1g1 f8e7", + "g1f3 g8f6 c2c4 c7c5 g2g3", + "g1f3 g8f6 c2c4 e7e6 b1c3 d7d5 d2d4 b8d7", + "g1f3 g8f6 c2c4 e7e6 b1c3 d7d5 d2d4 c7c5", + "g1f3 g8f6 c2c4 e7e6 b1c3 d7d5 d2d4 c7c6 c1g5", + "g1f3 g8f6 c2c4 e7e6 b1c3 d7d5 d2d4 c7c6 e2e3 b8d7 d1c2 f8d6", + "g1f3 g8f6 c2c4 e7e6 b1c3 d7d5 d2d4 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "g1f3 g8f6 c2c4 e7e6 b1c3 d7d5 d2d4 f8b4", + "g1f3 g8f6 c2c4 e7e6 b1c3 d7d5 d2d4 f8e7 c1f4 e8g8 e2e3", + "g1f3 g8f6 c2c4 e7e6 b1c3 d7d5 d2d4 f8e7 c1g5 e8g8 e2e3 h7h6", + "g1f3 g8f6 c2c4 e7e6 b1c3 d7d5 d2d4 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "g1f3 g8f6 c2c4 e7e6 g2g3 d7d5 f1g2 f8e7", + "g1f3 g8f6 c2c4 g7g6 b1c3 f8g7 e2e4", + "g1f3 g8f6 c2c4 g7g6 g2g3 f8g7 f1g2 e8g8", + "g1f3 g8f6 d2d4 c7c5", + "g1f3 g8f6 d2d4 d7d5 c2c4 c7c6 b1c3 d5c4 a2a4 c8f5 e2e3 e7e6 f1c4", + "g1f3 g8f6 d2d4 d7d5 c2c4 c7c6 b1c3 e7e6 c1g5", + "g1f3 g8f6 d2d4 d7d5 c2c4 c7c6 b1c3 e7e6 e2e3 b8d7 d1c2 f8d6", + "g1f3 g8f6 d2d4 d7d5 c2c4 c7c6 b1c3 e7e6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "g1f3 g8f6 d2d4 d7d5 c2c4 c7c6 e2e3", + "g1f3 g8f6 d2d4 d7d5 c2c4 d5c4 e2e3 e7e6 f1c4 c7c5 e1g1 a7a6", + "g1f3 g8f6 d2d4 d7d5 c2c4 e7e6 b1c3 b8d7", + "g1f3 g8f6 d2d4 d7d5 c2c4 e7e6 b1c3 c7c5", + "g1f3 g8f6 d2d4 d7d5 c2c4 e7e6 b1c3 c7c6 c1g5", + "g1f3 g8f6 d2d4 d7d5 c2c4 e7e6 b1c3 c7c6 e2e3 b8d7 d1c2 f8d6", + "g1f3 g8f6 d2d4 d7d5 c2c4 e7e6 b1c3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "g1f3 g8f6 d2d4 d7d5 c2c4 e7e6 b1c3 f8b4", + "g1f3 g8f6 d2d4 d7d5 c2c4 e7e6 b1c3 f8e7 c1f4 e8g8 e2e3", + "g1f3 g8f6 d2d4 d7d5 c2c4 e7e6 b1c3 f8e7 c1g5 e8g8 e2e3 h7h6", + "g1f3 g8f6 d2d4 d7d5 c2c4 e7e6 b1c3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "g1f3 g8f6 d2d4 d7d5 c2c4 e7e6 c1g5", + "g1f3 g8f6 d2d4 d7d5 c2c4 e7e6 g2g3", + "g1f3 g8f6 d2d4 e7e6 c1g5", + "g1f3 g8f6 d2d4 e7e6 c2c4 b7b6 a2a3 c8b7 b1c3 d7d5 c4d5 f6d5", + "g1f3 g8f6 d2d4 e7e6 c2c4 b7b6 b1c3 c8b7 a2a3 d7d5 c4d5 f6d5", + "g1f3 g8f6 d2d4 e7e6 c2c4 b7b6 b1c3 f8b4", + "g1f3 g8f6 d2d4 e7e6 c2c4 b7b6 g2g3 c8a6 b2b3 f8b4 c1d2 b4e7", + "g1f3 g8f6 d2d4 e7e6 c2c4 b7b6 g2g3 c8b7 f1g2 f8e7 e1g1 e8g8 b1c3 f6e4 d1c2 e4c3 c2c3", + "g1f3 g8f6 d2d4 e7e6 c2c4 c7c5 d4d5 e6d5 c4d5 d7d6 b1c3 g7g6", + "g1f3 g8f6 d2d4 e7e6 c2c4 d7d5 b1c3 b8d7", + "g1f3 g8f6 d2d4 e7e6 c2c4 d7d5 b1c3 c7c5", + "g1f3 g8f6 d2d4 e7e6 c2c4 d7d5 b1c3 c7c6 c1g5", + "g1f3 g8f6 d2d4 e7e6 c2c4 d7d5 b1c3 c7c6 e2e3 b8d7 d1c2 f8d6", + "g1f3 g8f6 d2d4 e7e6 c2c4 d7d5 b1c3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "g1f3 g8f6 d2d4 e7e6 c2c4 d7d5 b1c3 f8b4", + "g1f3 g8f6 d2d4 e7e6 c2c4 d7d5 b1c3 f8e7 c1f4 e8g8 e2e3", + "g1f3 g8f6 d2d4 e7e6 c2c4 d7d5 b1c3 f8e7 c1g5 e8g8 e2e3 h7h6", + "g1f3 g8f6 d2d4 e7e6 c2c4 d7d5 b1c3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "g1f3 g8f6 d2d4 e7e6 c2c4 d7d5 c1g5", + "g1f3 g8f6 d2d4 e7e6 c2c4 d7d5 g2g3", + "g1f3 g8f6 d2d4 e7e6 c2c4 f8b4 b1d2", + "g1f3 g8f6 d2d4 e7e6 c2c4 f8b4 c1d2", + "g1f3 g8f6 d2d4 e7e6 g2g3", + "g1f3 g8f6 d2d4 g7g6 c1g5", + "g1f3 g8f6 d2d4 g7g6 c2c4 f8g7 b1c3 e8g8 e2e4 d7d6 f1e2 e7e5 e1g1 b8c6 d4d5 c6e7 f3e1 f6d7", + "g1f3 g8f6 d2d4 g7g6 c2c4 f8g7 g2g3 e8g8 f1g2 d7d6 e1g1", + "g1f3 g8f6 d2d4 g7g6 g2g3 f8g7 f1g2 e8g8", + "g1f3 g8f6 g2g3 g7g6", +}; + +// Returns bool. If true, then book[start] to book[end-1] inclusive will +// match line. So end-start is the number of matching lines. +int book_range(char *line, int *startp, int *endp) +{ + unsigned int start, end; + if (ARRAY_SIZE(book) == 0) return 0; // no book?? + /* Find start. */ + for (start = 0; start < ARRAY_SIZE(book); start++) { + int result = strncmp(book[start], line, strlen(line)); + if (result < 0) + continue; // not yet + else if (result > 0) + break; // line not in book at all + // OK, found start. + for (end = start + 1; end < ARRAY_SIZE(book); end++) { + int result = strncmp(book[end], line, strlen(line)); + if (result > 0) + break; + else + assert(result == 0 && "opening book not sorted :("); + } + // Found end. + *startp = start; + *endp = end; + return 1; + } + return 0; // line not found +} + +int book_enabled = 1; + +/** + * Get a move from the book. Line is a string like "e2e4 e7e5 g1f3 " - note + * the space at the end! and the board is for passing to move_islegal. + */ +move_t book_move(char *line, board_t *board) +{ + int start, end; + if (!book_enabled) return 0; + if (book_range(line, &start, &end)) { + char book_move_str[BOOK_MOVE_LENGTH+1]; + move_t book_move; + unsigned long move_index; + static int rand_inited = 0; + char *errmsg; + if (!rand_inited) { + sgenrand((unsigned long)get_ticks()); + rand_inited = 1; + } + assert(end - start > 0); + move_index = (genrand() % (end-start)) + start; + strncpy(book_move_str, &book[move_index][strlen(line)], + BOOK_MOVE_LENGTH); + book_move_str[BOOK_MOVE_LENGTH] = 0; + book_move = move_islegal(board, book_move_str, &errmsg); + if (!book_move) { + set_cursor_pos(0,0); + printf("BUG: please email bblum@cs.cmu.edu the following: \n"); + printf("Line: \"%s\"\n", line); + printf("Attempted book line: \"%s\"\n", book[move_index]); + printf("Attempted move: \"%s\"\n", book_move_str); + assert(0 && "Illegal line in opening book?"); + } + return book_move; + } else { + return 0; + } +} +/**************************************************************************** + * engine.c - wrapper functions for managing computer vs human play + * copyright (C) 2008 Ben Blum + ****************************************************************************/ + +#define ENGINE_REPEATED_BUCKETS 127 + +/* from xboard.c, for printing */ +// void output(char *); + +/** + * Initialize a game engine given the searching function, with a new board + */ +engine_t *engine_init(search_fn search) +{ + engine_t *e = malloc(sizeof(engine_t)); + affirm_msg(e, "Couldn't allocate game engine"); + e->board = board_init(); + e->search = search; + e->line[0] = '\0'; + e->line_moves = 0; + e->inbook = 1; + return e; +} + +#define SEARCHTIME_DEFAULT 5 +#define SEARCHTIME_MAX 60 +unsigned int searchtime = SEARCHTIME_DEFAULT; + +extern int outbuf_size; +extern int text_loud; +extern char outbuf[]; +void output(); + +/** + * Have the engine generate a move for the side to play. String must be freed. + */ +char *engine_generatemove(engine_t *e) +{ + if (e->inbook) + { + move_t move = book_move(e->line, e->board); + if (move) + { + /* book lookup was successful */ + // output("ENGINE: Book lookup successful"); + char *str = move_tostring(move); + if (text_loud) { + snprintf(outbuf, outbuf_size, + "My move: %s (from opening book)", str); + output(); + } + return str; + } + else + { + /* we've left the book lines */ + // output("ENGINE: Leaving opening book lines"); + e->inbook = 0; + } + } + /* we get here if already out of book or if we just left book */ + return move_tostring(e->search(e->board, searchtime, NULL, NULL)); +} + +/** + * Change the board to reflect a move being made. Returns 1 if the move is + * illegal, 0 if it's good + */ +int engine_applymove(engine_t *e, char *str, char **errmsg) +{ + /* we need to make the move before adding, else we won't detect draws + * before they actually are called */ + move_t move = move_islegal(e->board, str, errmsg); + if (move == 0) { + return 0; + } + /* keep track of the game's line, but only if not too long */ + if (strlen(e->line) < BOOK_LINE_MAX_LENGTH-6) { + strcat(e->line, str); + strcat(e->line, " "); + assert(e->line_moves == e->board->moves); + e->line_moves++; + } + + board_applymove(e->board, move); + + return 1; +} + +void engine_undomove(engine_t *e) +{ + assert(e->board->moves > 0); + if (e->line_moves == e->board->moves) { + int i = strlen(e->line)-1; + assert(i > 0); + assert(e->line[i] == ' '); + if (e->line_moves == 1) { + e->line[0] = 0; + } else { + for (i--; i > 0 && e->line[i] != ' '; i--) { continue; } + assert(i > 0); + e->line[i+1] = 0; + } + e->line_moves--; + } + e->inbook = 1; // Not necessarily true. But it can't hurt. + board_undomove(e->board, e->board->history[e->board->moves-1].move); +} + +void engine_destroy(engine_t *e) +{ + if (e == NULL) + { + return; + } + board_destroy(e->board); + free(e); + return; +} +/**************************************************************************** + * eval.c - evaluation function to tell how good a position is + * copyright (C) 2008 Ben Blum + ****************************************************************************/ + +/* endgame starts when both sides have <= LIM_ENDGAME */ +#define EVAL_LIM_ENDGAME 1600 +/* use this limit when no queens on the board */ +#define EVAL_LIM_ENDGAME2 2000 + +#define EVAL_CASTLE_BONUS 20 + +int16_t eval_piecevalue[6] = { 100, 300, 300, 500, 900, 0 }; +int16_t eval_piecevalue_endgame[6] = { 125, 300, 300, 550, 1200, 0 }; + +/* Players get small point bonuses if their pieces are on good squares. If + * white has a rook on d1, squarevalue[WHITE][ROOK][D1] will be added to + * white's score. */ +/* Differences between src/dest squares are considered when ordering moves, so + * it is important that for any legal (src,dest) pair, abs(sqval(dest) - + * sqval(src)) <= SOME_CONSTANT - that constant is 16 for now. (only in the + * regular tables, not the endgame tables) */ +int16_t eval_squarevalue[2][6][64] = { + /******************************************************************** + * WHITE + ********************************************************************/ + { + /* PAWN */ + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, -4, -4, 4, 0, 0, + 6, 2, 3, 4, 4, 3, 2, 8, + 3, 4, 12, 12, 12, 8, 4, 3, + 5, 8, 16, 20, 20, 16, 8, 5, + 20, 24, 24, 32, 32, 24, 24, 20, + 36, 36, 40, 40, 40, 40, 36, 36, + 0, 0, 0, 0, 0, 0, 0, 0 + }, + /* KNIGHT */ + { + -10, -6, -6, -6, -6, -6, -6,-10, + -6, 0, 0, 3, 3, 0, 0, -6, + -6, 0, 8, 4, 4, 10, 0, -6, + -6, 0, 8, 10, 10, 8, 0, -6, + -4, 0, 8, 10, 10, 8, 0, -4, + -4, 5, 12, 12, 12, 12, 5, -4, + -4, 0, 5, 3, 3, 5, 0, -4, + -10, -4, -4, -4, -4, -4, -4,-10 + }, + /* BISHOP */ + { + -6, -5, -5, -5, -5, -5, -5, -6, + -5, 10, 5, 8, 8, 5, 10, -5, + -5, 5, 3, 5, 5, 3, 5, -5, + -5, 3, 10, 3, 3, 10, 3, -5, + -5, 5, 10, 3, 3, 10, 5, -5, + -5, 3, 8, 8, 8, 8, 3, -5, + -5, 5, 5, 8, 8, 5, 5, -5, + -6, -5, -5, -5, -5, -5, -5, -6 + }, + /* ROOK */ + { + 0, 3, 3, 3, 3, 3, 3, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 2, 2, 2, 1, 0, + 3, 5, 8, 8, 8, 8, 5, 3, + 0, 0, 0, 0, 0, 0, 0, 0 + }, + /* QUEEN */ + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + }, + /* KING */ + { + 5, 5, 8, 0, 0, -5, 10, 10, + 0, 0, 0, 0, 0, 0, 5, 5, + 0, 0, 0, -5, -5, 0, 0, 0, + 0, 0, -5,-10,-10, -5, 0, 0, + 0, -5,-10,-10,-10,-10, -5, 0, + -5,-10,-10,-15,-15,-10,-10, -5, + -20,-20,-20,-20,-20,-20,-20,-20, + -20,-20,-20,-20,-20,-20,-20,-20 + } + }, + /******************************************************************** + * BLACK + ********************************************************************/ + { + /* PAWN */ + { + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 36, 40, 40, 40, 40, 36, 36, + 20, 24, 24, 32, 32, 24, 24, 20, + 5, 8, 16, 20, 20, 16, 8, 5, + 3, 4, 12, 12, 12, 8, 4, 3, + 6, 2, 3, 4, 4, 3, 2, 8, + 0, 0, 0, -4, -4, 4, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + }, + /* KNIGHT */ + { + -10, -4, -4, -4, -4, -4, -4,-10, + -4, 0, 5, 3, 3, 5, 0, -4, + -4, 5, 12, 12, 12, 12, 5, -4, + -4, 0, 8, 10, 10, 8, 0, -4, + -6, 0, 8, 10, 10, 8, 0, -6, + -6, 0, 8, 4, 4, 10, 0, -6, + -6, 0, 0, 3, 3, 0, 0, -6, + -10, -6, -6, -6, -6, -6, -6,-10 + }, + /* BISHOP */ + { + -6, -5, -5, -5, -5, -5, -5, -6, + -5, 5, 5, 8, 8, 5, 5, -5, + -5, 5, 8, 8, 8, 8, 5, -5, + -5, 3, 10, 5, 5, 10, 3, -5, + -5, 5, 10, 5, 5, 10, 5, -5, + -5, 3, 3, 5, 5, 3, 3, -5, + -5, 10, 5, 8, 8, 5, 10, -5, + -6, -5, -5, -5, -5, -5, -5, -6 + }, + /* ROOK */ + { + 0, 0, 0, 0, 0, 0, 0, 0, + 3, 5, 8, 8, 8, 8, 5, 3, + 0, 1, 2, 2, 2, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 3, 3, 3, 3, 3, 3, 0 + }, + /* QUEEN */ + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + }, + /* KING */ + { + -20,-20,-20,-20,-20,-20,-20,-20, + -20,-20,-20,-20,-20,-20,-20,-20, + -5,-10,-10,-15,-15,-10,-10, -5, + 0, -5,-10,-10,-10,-10, -5, 0, + 0, 0, -5,-10,-10, -5, 0, 0, + 0, 0, 0, -5, -5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 5, 5, + 5, 5, 8, 0, 0, -5, 10, 10 + } + } +}; +int16_t eval_squarevalue_endgame[2][6][64] = { + /******************************************************************** + * WHITE + ********************************************************************/ + { + /* PAWN */ + { + 0, 0, 0, 0, 0, 0, 0, 0, + -10,-10,-10,-10,-10,-10,-10,-10, + 0, 0, 0, 0, 0, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 10, 10, + 20, 20, 20, 20, 20, 20, 20, 20, + 40, 40, 40, 40, 40, 40, 40, 40, + 80, 80, 80, 80, 80, 80, 80, 80, + 0, 0, 0, 0, 0, 0, 0, 0 + }, + /* KNIGHT */ + { + -10, -5, -5, -5, -5, -5, -5,-10, + -8, 0, 0, 3, 3, 0, 0, -8, + -8, 0, 10, 8, 8, 10, 0, -8, + -8, 0, 8, 10, 10, 8, 0, -8, + -8, 0, 8, 10, 10, 8, 0, -8, + -8, 0, 12, 12, 12, 12, 0, -8, + -8, 0, 9, 3, 3, 9, 0, -8, + -10, -5, -5, -5, -5, -5, -5,-10 + }, + /* BISHOP */ + { + -8, -5, -5, -5, -5, -5, -5, -8, + -5, 3, 5, 5, 5, 5, 3, -5, + -5, 5, 5, 8, 8, 5, 5, -5, + -5, 5, 10, 10, 10, 10, 5, -5, + -5, 5, 10, 10, 10, 10, 5, -5, + -5, 3, 8, 8, 8, 8, 3, -5, + -5, 3, 5, 8, 8, 5, 3, -5, + -8, -5, -5, -5, -5, -5, -5, -8 + }, + /* ROOK */ + { + 0, 3, 3, 5, 5, 3, 3, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 2, 2, 2, 1, 0, + 1, 3, 5, 5, 5, 5, 3, 1, + 0, 0, 0, 0, 0, 0, 0, 0 + }, + /* QUEEN */ + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + }, + /* KING */ + { + -25,-15,-10,-10,-10,-10,-15,-25, + -15, -5, 0, 0, 0, 0, -5,-15, + -10, 0, 5, 10, 10, 5, 0,-10, + -10, 0, 10, 15, 15, 10, 0,-10, + -5, 5, 15, 20, 20, 15, 5, -5, + 0, 10, 20, 20, 20, 15, 10, 0, + -15, 0, 5, 5, 5, 5, 0,-15, + -25,-15,-10,-10,-10,-10,-15,-25 + } + }, + /******************************************************************** + * BLACK + ********************************************************************/ + { + /* PAWN */ + { + 0, 0, 0, 0, 0, 0, 0, 0, + 80, 80, 80, 80, 80, 80, 80, 80, + 40, 40, 40, 40, 40, 40, 40, 40, + 20, 20, 20, 20, 20, 20, 20, 20, + 10, 10, 10, 10, 10, 10, 10, 10, + 0, 0, 0, 0, 0, 0, 0, 0, + -10,-10,-10,-10,-10,-10,-10,-10, + 0, 0, 0, 0, 0, 0, 0, 0 + }, + /* KNIGHT */ + { + -10, -5, -5, -5, -5, -5, -5,-10, + -8, 0, 9, 3, 3, 9, 0, -8, + -8, 0, 12, 12, 12, 12, 0, -8, + -8, 0, 8, 10, 10, 8, 0, -8, + -8, 0, 8, 10, 10, 8, 0, -8, + -8, 0, 10, 8, 8, 10, 0, -8, + -8, 0, 0, 3, 3, 0, 0, -8, + -10, -5, -5, -5, -5, -5, -5,-10 + }, + /* BISHOP */ + { + -8, -5, -5, -5, -5, -5, -5, -8, + -5, 3, 5, 8, 8, 5, 3, -5, + -5, 3, 8, 8, 8, 8, 3, -5, + -5, 5, 10, 10, 10, 10, 5, -5, + -5, 5, 10, 10, 10, 10, 5, -5, + -5, 5, 5, 8, 8, 5, 5, -5, + -5, 3, 5, 5, 5, 5, 3, -5, + -8, -5, -5, -5, -5, -5, -5, -8 + }, + /* ROOK */ + { + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 3, 5, 5, 5, 5, 3, 1, + 0, 1, 2, 2, 2, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 3, 3, 5, 5, 3, 3, 0 + }, + /* QUEEN */ + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + }, + /* KING */ + { + -25,-15,-10,-10,-10,-10,-15,-25 + -15, 0, 5, 5, 5, 5, 0,-15, + 0, 10, 20, 20, 20, 15, 10, 0, + -5, 5, 15, 20, 20, 15, 5, -5, + -10, 0, 10, 15, 15, 10, 0,-10, + -10, 0, 5, 10, 10, 5, 0,-10, + -15, -5, 0, 0, 0, 0, -5,-15, + -25,-15,-10,-10,-10,-10,-15,-25, + } + } +}; + +static int16_t eval_endgame(board_t *); + +/* Penalty for trapping the d- e- pawns on 2nd rank, or c-pawn with the knight + * if there's a pawn on d4 and no pawn on e4 */ +#define EVAL_BLOCKED_PAWN -25 +/* used for pawn-block checking N on c3 with pawns c2 d4 !e4 */ +#define BB_C2D4 (BB_SQUARE(C2) | BB_SQUARE(D4)) +#define BB_C2D4E4 (BB_C2D4 | BB_SQUARE(E4)) +#define BB_C7D5 (BB_SQUARE(C7) | BB_SQUARE(D5)) +#define BB_C7D5E5 (BB_C7D5 | BB_SQUARE(E5)) +/* reward the bishop pair and penalize the knight pair */ +#define EVAL_BISHOP_PAIR 20 +#define EVAL_KNIGHT_PAIR -20 +/* Rooks like to see towards the other end of the board */ +#define EVAL_ROOK_OPENFILE 10 +#define EVAL_ROOK_OPENFILE_MULTIPLIER 3 +/* bonus for having multiple rooks on the 7th - take the number of heavies + * on the 7th, leftshift this constant by that number */ +#define EVAL_ROOK_RANK7_MULTIPLIER 12 +/* bonus for having a minor piece on an "outpost" - a hole in the opp's pawn + * structure protected by one of own pawns. */ +#define EVAL_OUTPOST_BONUS 32 + +/************** + * King safety + **************/ +/* Points for having N pawns on rank 2/3 in front of a castled king*/ +static int16_t pawncover_rank2[4] = { -80, -40, 0, 5 }; +static int16_t pawncover_rank3[4] = { 0, 5, 20, 40 }; +/* penalty for having no pawns on king's file */ +#define EVAL_KINGFILEOPEN -35 +/* penalty for having no pawns on file adjacent to king's file */ +#define EVAL_ADJACENTFILEOPEN -15 + +/* tropism bonus from one square to another (one square has a piece of given + * type on it, the other has the enemy king) */ +#define EVAL_TROPISM_MAX 192 +/* this lookup array gives shiftamounts for distance so we don't have to idiv + * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 */ +static int tropism_rice[15] = { 0, 0, 0, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5}; +/* this lookup array gives shiftamounts for scaling by piece value + * P N B R Q K */ +static int tropism_piecescale[6] = { 3, 2, 2, 1, 0, 0 }; + +static int16_t tropism(square_t a, square_t b, piece_t piece) +{ + int16_t rowdist, coldist; + /* absolute values of the difference between the two squares */ + rowdist = ROW(a) - ROW(b); + if (rowdist < 0) { rowdist = -rowdist; } + coldist = COL(a) - COL(b); + if (coldist < 0) { coldist = -coldist; } + /* score inversely proportional to distance, also scaled by how + * heavy the piece is - queen right up against the opp king will + * get like 100 points */ + return (EVAL_TROPISM_MAX >> tropism_rice[rowdist + coldist]) >> + tropism_piecescale[piece]; +} + +int eval_isendgame(board_t *board) +{ + if (board->pos[WHITE][QUEEN] | board->pos[BLACK][QUEEN]) + { + return (board->material[WHITE] <= EVAL_LIM_ENDGAME) || + (board->material[BLACK] <= EVAL_LIM_ENDGAME); + } + return (board->material[WHITE] <= EVAL_LIM_ENDGAME2) || + (board->material[BLACK] <= EVAL_LIM_ENDGAME2); +} + +/** + * Evaluate - return a score for the given position for who's to move + */ +int16_t eval(board_t *board) +{ + int piece, square; + bitboard_t piecepos; + /* keeps track of {WHITE,BLACK}s score */ + int16_t score_white, score_black; + /* king safety scores - scaled by the material on the board to + * encourage trading when under attack */ + int16_t ksafety_white, ksafety_black; + square_t kingsq_white, kingsq_black; /* where's each king */ + /* counting pieces/pawns for king safety */ + int num_pieces; + /* holes in <color>'s pawnstructure */ + bitboard_t holes_white, holes_black; + + /* use the special endgame evaluator if in the endgame */ + if (eval_isendgame(board)) + { + return eval_endgame(board); + } + + /* begin evaluating */ + score_white = 0; score_black = 0; + ksafety_white = 0; ksafety_black = 0; + kingsq_white = BITSCAN(board->pos[WHITE][KING]); + kingsq_black = BITSCAN(board->pos[BLACK][KING]); + + /******************************************************************** + * Piece/square tables + ********************************************************************/ + /******** + * White + ********/ + /* regular pieces - pawns taken care of in pawnstructure eval */ + for (piece = 1; piece < 5; piece++) + { + piecepos = board->pos[WHITE][piece]; + while (piecepos) + { + square = BITSCAN(piecepos); + piecepos ^= BB_SQUARE(square); + score_white += eval_squarevalue[WHITE][piece][square]; + /* tropism scores - how close is to our/opp king? */ + //ksafety_white += tropism(square, kingsq_white, piece); + ksafety_black -= tropism(square, kingsq_black, piece); + /* Rooks like open files */ + if (piece == ROOK) + { + /* no pawns on this file */ + if (!(board->pos[WHITE][PAWN] & BB_FILE(COL(square)))) + { + score_white += EVAL_ROOK_OPENFILE; + } + /* how far can we see? */ + score_white += EVAL_ROOK_OPENFILE_MULTIPLIER * POPCOUNT(colattacks[(board->occupied90 >> (8 * COL(square))) & 0xFF][ROW(square)]); + } + } + } + /* king */ + score_white += eval_squarevalue[WHITE][KING][kingsq_white]; + + /******** + * Black + ********/ + for (piece = 1; piece < 5; piece++) + { + piecepos = board->pos[BLACK][piece]; + while (piecepos) + { + square = BITSCAN(piecepos); + piecepos ^= BB_SQUARE(square); + score_black += eval_squarevalue[BLACK][piece][square]; + /* tropism scores - how close is to our/opp king? */ + ksafety_white -= tropism(square, kingsq_white, piece); + //ksafety_black += tropism(square, kingsq_black, piece); + /* Rooks like open files */ + if (piece == ROOK) + { + /* no pawns on this file */ + if (!(board->pos[BLACK][PAWN] & BB_FILE(COL(square)))) + { + score_black += EVAL_ROOK_OPENFILE; + } + /* how far can we see? */ + score_black += EVAL_ROOK_OPENFILE_MULTIPLIER * POPCOUNT(colattacks[(board->occupied90 >> (8 * COL(square))) & 0xFF][ROW(square)]); + } + } + } + /* king */ + score_black += eval_squarevalue[BLACK][KING][kingsq_white]; + + /******************************************************************** + * Misc. bonuses + ********************************************************************/ + /* bishop/knight pair bonus/penalties */ + if (POPCOUNT(board->pos[WHITE][BISHOP]) > 1) { score_white += EVAL_BISHOP_PAIR; } + if (POPCOUNT(board->pos[WHITE][KNIGHT]) > 1) { score_white += EVAL_KNIGHT_PAIR; } + if (POPCOUNT(board->pos[BLACK][BISHOP]) > 1) { score_black += EVAL_BISHOP_PAIR; } + if (POPCOUNT(board->pos[BLACK][KNIGHT]) > 1) { score_black += EVAL_KNIGHT_PAIR; } + /* pawnstructure bonus */ + score_white += eval_pawnstructure(board, WHITE, &holes_white); + score_black += eval_pawnstructure(board, BLACK, &holes_black); + /* analysis of pawnstructure holes - all holes that our pawns attack + * and have a minor piece on them get an "outpost" bonus - don't allow + * bonus for outposts on the A and H files */ + /* find white's outposts */ + holes_black &= board_pawnattacks(board->pos[WHITE][PAWN], WHITE) & + (board->pos[WHITE][KNIGHT] | board->pos[WHITE][BISHOP]) & + ~(BB_FILEA | BB_FILEH); + score_white += EVAL_OUTPOST_BONUS * POPCOUNT(holes_black); + /* find black's outposts */ + holes_white &= board_pawnattacks(board->pos[BLACK][PAWN], BLACK) & + (board->pos[BLACK][KNIGHT] | board->pos[BLACK][BISHOP]) & + ~(BB_FILEA | BB_FILEH); + score_black += EVAL_OUTPOST_BONUS * POPCOUNT(holes_white); + /* pawn block penalties */ + if (((board->piecesofcolor[WHITE] ^ board->pos[WHITE][PAWN]) & BB_SQUARE(D3)) && + (board->pos[WHITE][PAWN] & BB_SQUARE(D2))) /* blocked on D2 */ + { + score_white += EVAL_BLOCKED_PAWN; + } + if (((board->piecesofcolor[WHITE] ^ board->pos[WHITE][PAWN]) & BB_SQUARE(E3)) && + (board->pos[WHITE][PAWN] & BB_SQUARE(E2))) /* blocked on E2 */ + { + score_white += EVAL_BLOCKED_PAWN; + } + if ((board->pos[WHITE][KNIGHT] & BB_SQUARE(C3)) && /* knight on C3 */ + !((board->pos[WHITE][PAWN] ^ BB_C2D4) & BB_C2D4E4)) /* "closed" opening */ + { + score_white += EVAL_BLOCKED_PAWN; + } + /* black */ + if (((board->piecesofcolor[BLACK] ^ board->pos[BLACK][PAWN]) & BB_SQUARE(D6)) && + (board->pos[BLACK][PAWN] & BB_SQUARE(D7))) /* blocked on D7 */ + { + score_black += EVAL_BLOCKED_PAWN; + } + if (((board->piecesofcolor[BLACK] ^ board->pos[BLACK][PAWN]) & BB_SQUARE(E6)) && + (board->pos[BLACK][PAWN] & BB_SQUARE(E7))) /* blocked on E7 */ + { + score_black += EVAL_BLOCKED_PAWN; + } + if ((board->pos[BLACK][KNIGHT] & BB_SQUARE(C6)) && /* knight on C6 */ + !((board->pos[BLACK][PAWN] ^ BB_C7D5) & BB_C7D5E5)) /* "closed" defense */ + { + score_black += EVAL_BLOCKED_PAWN; + } + /* rook/queen on the 7th bonus */ + score_white += EVAL_ROOK_RANK7_MULTIPLIER << + POPCOUNT((board->pos[WHITE][ROOK] | board->pos[WHITE][QUEEN]) & + BB_RANK7); + score_black += EVAL_ROOK_RANK7_MULTIPLIER << + POPCOUNT((board->pos[BLACK][ROOK] | board->pos[BLACK][QUEEN]) & + BB_RANK2); + + /******************************************************************** + * King safety - white + ********************************************************************/ + /* pawn shield */ + if (board->hascastled[WHITE]) + { + ksafety_white += EVAL_CASTLE_BONUS; + /* pawn shield one row in front of the king */ + num_pieces = POPCOUNT(kingattacks[kingsq_white] & + board->pos[WHITE][PAWN] & BB_RANK2); + ksafety_white += pawncover_rank2[num_pieces]; + /* pawn shield two rows in front of the king */ + num_pieces = POPCOUNT(kingattacks[kingsq_white + 8] & + board->pos[WHITE][PAWN] & BB_RANK3); + ksafety_white += pawncover_rank3[num_pieces]; + } + /* open files near the king */ + if (!(board->pos[WHITE][PAWN] & BB_FILE(COL(kingsq_white)))) + { + ksafety_white += EVAL_KINGFILEOPEN; + } + switch(COL(kingsq_white)) /* this idea taken from gnuchess */ + { + case COL_A: + case COL_E: + case COL_F: + case COL_G: + if (!(board->pos[WHITE][PAWN] & BB_FILE(COL(kingsq_white) + 1))) + { + ksafety_white += EVAL_ADJACENTFILEOPEN; + } + break; + case COL_H: + case COL_D: + case COL_C: + case COL_B: + if (!(board->pos[WHITE][PAWN] & BB_FILE(COL(kingsq_white) - 1))) + { + ksafety_white += EVAL_ADJACENTFILEOPEN; + } + break; + default: + break; + } + score_white += ksafety_white * board->material[BLACK] / 3100; + /******************************************************************** + * King safety - black + ********************************************************************/ + /* pawn shield */ + if (board->hascastled[BLACK]) + { + ksafety_black += EVAL_CASTLE_BONUS; + /* pawn shield one row in front of the king */ + num_pieces = POPCOUNT(kingattacks[kingsq_black] & + board->pos[BLACK][PAWN] & BB_RANK7); + ksafety_black += pawncover_rank2[num_pieces]; + /* pawn shield two rows in front of the king */ + num_pieces = POPCOUNT(kingattacks[kingsq_black - 8] & + board->pos[BLACK][PAWN] & BB_RANK6); + ksafety_black += pawncover_rank3[num_pieces]; + } + /* open files near the king */ + if (!(board->pos[BLACK][PAWN] & BB_FILE(COL(kingsq_black)))) + { + ksafety_black += EVAL_KINGFILEOPEN; + } + switch(COL(kingsq_black)) /* this idea taken from gnuchess */ + { + case COL_A: + case COL_E: + case COL_F: + case COL_G: + if (!(board->pos[BLACK][PAWN] & BB_FILE(COL(kingsq_black) + 1))) + { + ksafety_black += EVAL_ADJACENTFILEOPEN; + } + break; + case COL_H: + case COL_D: + case COL_C: + case COL_B: + if (!(board->pos[BLACK][PAWN] & BB_FILE(COL(kingsq_black) - 1))) + { + ksafety_black += EVAL_ADJACENTFILEOPEN; + } + break; + default: + break; + } + score_black += ksafety_black * board->material[WHITE] / 3100; + /******************************************************************** + * return the values + ********************************************************************/ + if (board->tomove == WHITE) + { + return (score_white + board->material[WHITE]) - + (score_black + board->material[BLACK]); + } + else + { + return (score_black + board->material[BLACK]) - + (score_white + board->material[WHITE]); + } +} + +/** + * Special-case endgame evaluator + */ +static int16_t eval_endgame(board_t *board) +{ + int piece, square; + bitboard_t piecepos; + /* keeps track of {WHITE,BLACK}s score */ + int16_t score_white = 0, score_black = 0; + int16_t difference = board->material[WHITE] - + board->material[BLACK]; + + /* draw evaluation - if no pawns are left, many possibilities + * note, our goal in this if block is to put the conditionals most + * likely to fail first, so we don't waste time saying "is the pawn's + * promotion square the opposite color of the bishop" when there's a + * queen on the board. */ + if (!(board->pos[WHITE][PAWN] | board->pos[BLACK][PAWN])) + { + /* absolute value */ + if (difference < 0) { difference = -difference; } + + /* a good heuristic to use is if the material difference is + * less than 400, the position is drawn */ + if (difference < 400) + { + return 0; + } + + /* KNN vs K */ + else if (difference == 600) + { + /* check if white has the two knights */ + if ((board->material[BLACK] == 0) && + (board->piecesofcolor[WHITE] == + (board->pos[WHITE][KING] | + board->pos[WHITE][KNIGHT]))) + { + return 0; + } + /* or black has the two knights */ + if ((board->material[WHITE] == 0) && + (board->piecesofcolor[BLACK] == + (board->pos[BLACK][KING] | + board->pos[BLACK][KNIGHT]))) + { + return 0; + } + /* here it must be a different piece configuration */ + } + } + /* KB + wrong color rook pawn vs K */ + else if (difference == 400) + { + /* first make sure it's KB rookpawn v K */ + if ((board->material[BLACK] == 0) && + (board->pos[WHITE][BISHOP] != BB(0x0)) && + (board->pos[WHITE][PAWN] & (COL_A | COL_H))) + { + square_t pawnsquare = BITSCAN(board->pos[WHITE][PAWN]); + square_t bishopsquare = BITSCAN(board->pos[WHITE][BISHOP]); + square_t promotionsquare = SQUARE(COL(pawnsquare),RANK_8); + /* check the square parities and also where's + * the enemy king */ + if ((PARITY(bishopsquare) != PARITY(promotionsquare)) && + (kingattacks[BITSCAN(board->pos[BLACK][KING])] & + BB_SQUARE(promotionsquare))) + { + return 0; + } + } + /* same thing for the other color */ + else if ((board->material[WHITE] == 0) && + (board->pos[BLACK][BISHOP] != BB(0x0)) && + (board->pos[BLACK][PAWN] & (COL_A | COL_H))) + { + square_t pawnsquare = BITSCAN(board->pos[BLACK][PAWN]); + square_t bishopsquare = BITSCAN(board->pos[BLACK][BISHOP]); + square_t promotionsquare = SQUARE(COL(pawnsquare),RANK_1); + /* check the square parities and also where's + * the enemy king */ + if ((PARITY(bishopsquare) != PARITY(promotionsquare)) && + (kingattacks[BITSCAN(board->pos[WHITE][KING])] & + BB_SQUARE(promotionsquare))) + { + return 0; + } + } + } + /* KP vs K - here we code just two cases, to facilitate the searcher; + * once we hit the back rank the searcher will see the draw itself. + * the first position is with the Ks in opposition with the pawn + * in between (either side to move, it's a draw); the second is + * with the pawn behind the winning king, in opposition (zugzwang) */ + else if (difference == 100) + { + /* white has the pawn */ + if (board->material[BLACK] == 0) + { + square_t whiteking = BITSCAN(board->pos[WHITE][KING]); + square_t blackking = BITSCAN(board->pos[BLACK][KING]); + square_t whitepawn = BITSCAN(board->pos[WHITE][PAWN]); + unsigned char pawncol = COL(whitepawn); + /* test for rook pawn draws */ + if (pawncol == COL_A || pawncol == COL_H) + { + /* if black king gets in front of the pawn, + * it's a draw no matter what */ + if ((COL(blackking) == pawncol) && + (blackking > whitepawn)) + { + return 0; + } + /* if the white king is in front of his pawn, + * but trapped by the black king, it'll end in + * stalemate */ + if (COL(whiteking) == pawncol) + { + if (pawncol == COL_A) + { + if (blackking - whiteking == 2) + { + return 0; + } + } + else /* pawncol == COL_H */ + { + if (whiteking - blackking == 2) + { + return 0; + } + } + } + } + if ((blackking - whiteking == 16) && + (ROW(blackking) != RANK_8)) + { + if (whitepawn - whiteking == 8) + { + return 0; + } + else if ((whiteking - whitepawn == 8) && + (board->tomove == WHITE)) + { + return 0; + } + } + } + /* black has the pawn */ + else if (board->material[WHITE] == 0) + { + square_t whiteking = BITSCAN(board->pos[WHITE][KING]); + square_t blackking = BITSCAN(board->pos[BLACK][KING]); + square_t blackpawn = BITSCAN(board->pos[BLACK][PAWN]); + unsigned char pawncol = COL(blackpawn); + /* test for rook pawn draws */ + if (pawncol == COL_A || pawncol == COL_H) + { + /* if black king gets in front of the pawn, + * it's a draw no matter what */ + if ((COL(whiteking) == pawncol) && + (whiteking < blackpawn)) + { + return 0; + } + /* if the white king is in front of his pawn, + * but trapped by the black king, it'll end in + * stalemate */ + if (COL(blackking) == pawncol) + { + if (pawncol == COL_A) + { + if (whiteking - blackking == 2) + { + return 0; + } + } + else /* pawncol == COL_H */ + { + if (blackking - whiteking== 2) + { + return 0; + } + } + } + } + if ((blackking - whiteking == 16) && + (ROW(whiteking) != RANK_1)) + { + if (blackking - blackpawn == 8) + { + return 0; + } + else if ((blackpawn - blackking == 8) && + (board->tomove == BLACK)) + { + return 0; + } + } + } + } + + /* calculate piece/square totals */ + for (piece = 0; piece < 6; piece++) + { + piecepos = board->pos[WHITE][piece]; + while (piecepos) + { + square = BITSCAN(piecepos); + piecepos ^= BB_SQUARE(square); + score_white += eval_piecevalue_endgame[piece] + + eval_squarevalue_endgame[WHITE][piece][square]; + } + } + for (piece = 0; piece < 6; piece++) + { + piecepos = board->pos[BLACK][piece]; + while (piecepos) + { + square = BITSCAN(piecepos); + piecepos ^= BB_SQUARE(square); + score_black += eval_piecevalue_endgame[piece] + + eval_squarevalue_endgame[BLACK][piece][square]; + } + } + + /* return the values - we revalued the pieces to make pawns more + * important so board->material is inaccurate here */ + if (board->tomove == WHITE) + { + return score_white - score_black; + } + else + { + return score_black - score_white; + } +} + +/** + * Lazy evaluator + */ +int16_t eval_lazy(board_t *board) +{ + return board->material[board->tomove] - + board->material[OTHERCOLOR(board->tomove)]; +} +/**************************************************************************** + * movelist.c - data structure for move sorting in move generation/iteration + * copyright (C) 2008 Ben Blum + * ****************************************************************************/ + +extern int16_t eval_squarevalue[2][6][64]; + +/* Material values, add/subtract to find indices for moves which change the + * material count */ +static uint8_t movelist_material[] = { 1, 3, 3, 5, 9, 12 }; + +/* arg 1 is the attacked boards, arg 2 is the move */ +static unsigned long movelist_findindex(uint64_t[2], uint32_t); + +/** + * Add a move. Determines where to add it using findindex + */ +void movelist_add(movelist_t *ml, uint64_t attackedby[2], uint32_t m) +{ + movelist_addtohead(ml, m, movelist_findindex(attackedby, m)); +} + +/** + * Determine at which index in the movelist a move should be added + */ +static unsigned long movelist_findindex(uint64_t attackedby[2], uint32_t m) +{ + int16_t materialgain; + /* which side has the move? this is a substitute for board->tomove */ + unsigned char tomove = MOV_COLOR(m); + + if (MOV_PROM(m)) + { + if (MOV_PROMPC(m) == QUEEN) + { + /* MOV_CAPT is 1 or 0 */ + return MOVELIST_INDEX_PROM_QUEEN + MOV_CAPT(m); + } + return MOVELIST_INDEX_PROM_MINOR; + } + if (MOV_CASTLE(m)) + { + /* The second term will be 1 if O-O, 0 if O-O-O */ + return MOVELIST_INDEX_CASTLE + (COL(MOV_DEST(m)) == COL_G); + } + if (MOV_CAPT(m)) + { + materialgain = movelist_material[MOV_CAPTPC(m)]; + /* see if the capturing piece will be recaptured - assume it + * will be if the opponent attacks that square at all */ + if (attackedby[OTHERCOLOR(tomove)] & BB_SQUARE(MOV_DEST(m))) + { + /* this will index past the end of the array if the + * moving piece is a king - we rely on the board + * library to filter out suicide king captures */ + materialgain -= movelist_material[MOV_PIECE(m)]; + /* neutral capture */ + if (materialgain == 0) + { + return MOVELIST_INDEX_NEUTRAL + MOV_PIECE(m); + } + //real SEE could be done here + } + /* losing material */ + else if (materialgain < 0) + { + return MOVELIST_INDEX_MAT_LOSS + materialgain; + } + /* winning capture */ + else + { + return MOVELIST_INDEX_MAT_GAIN + materialgain; + } + } + /* here it's a regular move */ + /* moving the piece where it can be captured */ + if (attackedby[OTHERCOLOR(tomove)] & BB_SQUARE(MOV_DEST(m))) + { + /* Moves that put the king in check are only generated if the + * attackedby bitmasks don't see it, so we won't fall apart on + * one either - they just get poor ordering, which is fine. */ + assert(MOV_PIECE(m) != KING); + /* if we can recapture after being captured */ + if (attackedby[tomove] & BB_SQUARE(MOV_DEST(m))) + { + /* if the moving piece is better than a pawn, call it + * a loss. otherwise, assume the pawn won't be taken + * (and fall through to the next phase). */ + if (MOV_PIECE(m) != PAWN) + { + /* give an "approximate" SEE - guessing, when + * we recapture we'll get between 1 and 3 */ + return MOVELIST_INDEX_MAT_LOSS + 2 - + movelist_material[MOV_PIECE(m)]; + } + //real SEE could be done here + } + /* if we move to a hanging square, we consider it complete + * loss of that piece */ + else + { + return MOVELIST_INDEX_MAT_LOSS - + movelist_material[MOV_PIECE(m)]; + } + } + /* here our piece is safe on its destination - let's see if we were + * saving it from being captured otherwise ("unhang"ing the piece); if + * so, it goes in the material gain category */ + if ((attackedby[OTHERCOLOR(tomove)] & ~(attackedby[tomove])) & + BB_SQUARE(MOV_SRC(m))) + { + return MOVELIST_INDEX_MAT_GAIN + + movelist_material[MOV_PIECE(m)]; + } + /* regular move */ + return MOVELIST_INDEX_REGULAR + + eval_squarevalue[tomove][MOV_PIECE(m)][MOV_DEST(m)] - + eval_squarevalue[tomove][MOV_PIECE(m)][MOV_SRC(m)]; +} + +void movelist_addtohead(movelist_t *mlp, uint32_t m, unsigned long index) +{ + movelist_inner_t *ml = *mlp; + /* sanity check */ + assert(index < MOVELIST_NUM_BUCKETS); + /* add to list */ + assert(ml->sublist_count[index] < MOVELIST_SUBLIST_LENGTH); + ml->array[index][ml->sublist_count[index]] = m; + ml->sublist_count[index]++; + + /* adjust max pointer */ + if (index > ml->max) + { + ml->max = index; + } + return; +} + +int movelist_isempty(movelist_t *mlp) +{ + movelist_inner_t *ml = *mlp; + return (ml->sublist_count[ml->max] == 0); +} + +/* Don't call this if movelist_isempty! */ +uint32_t movelist_remove_max(movelist_t *mlp) +{ + movelist_inner_t *ml = *mlp; + uint32_t returnval = ml->array[ml->max][--ml->sublist_count[ml->max]]; + /* check if we need to adjust the max pointer */ + while (movelist_isempty(mlp)) + { + /* we hit the bottom of the array; doesn't matter if empty */ + if (ml->max == 0) + { + break; + } + ml->max--; + } + return returnval; +} +/**************************************************************************** + * pawnstructure.c - evaluation helpers to judge pawn structure quality + * copyright (C) 2008 Ben Blum + * ****************************************************************************/ + +/* We do pawn square scoring here rather than in eval.c to save time */ +extern int16_t eval_squarevalue[2][6][64]; + +typedef struct ps_entry_t { + bitboard_t key; + bitboard_t holes; + int16_t value; +} ps_entry_t; + +/* this is a lot like the transposition table in case you haven't noticed... */ +#ifndef PS_NUM_BUCKETS +#define PS_NUM_BUCKETS (32 * 1024 * 1024 / sizeof(ps_entry_t)) // 32MB +#endif +static ps_entry_t ps_array[PS_NUM_BUCKETS]; + +static void ps_add(bitboard_t key, bitboard_t holes, int16_t value) +{ + unsigned long bucket; + + /* find the bucket */ + bucket = key % PS_NUM_BUCKETS; + /* always evict */ + ps_array[bucket].key = key; + ps_array[bucket].holes = holes; + ps_array[bucket].value = value; + + return; +} + +/** + * Fetch data from the table. + */ +#define PAWNSTRUCTURE_LOOKUP_FAIL INT16_MIN +static int16_t ps_get(bitboard_t key, bitboard_t *holes) +{ + unsigned long bucket = key % PS_NUM_BUCKETS; + if (ps_array[bucket].key == key) + { + *holes = ps_array[bucket].holes; + return ps_array[bucket].value; + } + return PAWNSTRUCTURE_LOOKUP_FAIL; +} + +/* Bonus for pawn chains - for each pawn protected by another, add bonus */ +#ifndef PS_CHAIN_BONUS +#define PS_CHAIN_BONUS 2 +#endif +/* Penalty for doubling pawns - for each pawn with another pawn on its file, + * subtract the penalty (note, tripled pawns net loss 6 times this!) */ +#ifndef PS_DOUBLED_PENALTY +#define PS_DOUBLED_PENALTY 8 +#endif +/* Isolated penalty - for each pawn with no brothers on adjacent files + * note, if a pawn gets this penalty it will also get the backwards penalty */ +#ifndef PS_ISOLATED_PENALTY +#define PS_ISOLATED_PENALTY 16 +#endif +/* Backward pawns - nothing on same rank or behind on adjacent columns */ +#ifndef PS_BACKWARD_PENALTY +#define PS_BACKWARD_PENALTY 8 +#endif + +/* Bonuses for having a passed pawn of <color> on the given <rank> */ +int16_t pawnstructure_passed_bonus[2][8] = { + { 0, 3, 6, 12, 24, 48, 96, 0 }, + { 0, 96, 48, 24, 12, 6, 3, 0 } +}; + +/** + * Pawnstructure evaluator - color being whose pawns these are, and holes a + * pass-by-reference second return value - a chart of all "holes" in the pawn + * structure; that is, all squares which can never be attacked by these pawns. + */ +int16_t eval_pawnstructure(board_t *board, unsigned char color, bitboard_t *h) +{ + /* the value we calculate and store in the hashtable */ + int16_t value; + /* value dependent on factors outside of just the pawn pos, so we + * cannot hash this and must calculate even if the cache hits */ + int16_t unhashable_bonus = 0; + + square_t square; + bitboard_t pawns, pos, friends, everybodyelse, behindmask, holes; + + pawns = board->pos[color][PAWN]; + + /* attempt to lookup - if we succeed, only need to calculate the + * unhashable bonus. pass in the h ptr as well; if the lookup + * fails it'll be untouched */ + if ((value = ps_get(pawns, h)) != PAWNSTRUCTURE_LOOKUP_FAIL) + { + while (pawns) + { + square = BITSCAN(pawns); + pawns ^= BB_SQUARE(square); + if (board_pawnpassed(board, square, color)) + { + unhashable_bonus += pawnstructure_passed_bonus[color][ROW(square)]; + } + } + return value + unhashable_bonus; + } + + /* holes starts with everything set, and we take off bits that our + * pawns could attack (using passedpawn masks for this) */ + holes = ~BB_SQUARE(0x0); + /* for each pawn, consider its value with relation to the structure */ + pos = pawns; + while (pos) + { + /* find and clear a bit */ + square = BITSCAN(pos); + pos ^= BB_SQUARE(square); + /* piece/square table */ + value += eval_squarevalue[color][PAWN][square]; + + /* check for passed pawn */ + if (board_pawnpassed(board, square, color)) + { + unhashable_bonus += pawnstructure_passed_bonus[color][ROW(square)]; + } + + everybodyelse = pawns ^ BB_SQUARE(square); + + /* first evaluate chaining */ + friends = everybodyelse & pawnattacks[color][square]; + value += PS_CHAIN_BONUS * POPCOUNT(friends); + + /* next, doubled pawns */ + friends = everybodyelse & BB_FILE(COL(square)); + value -= PS_DOUBLED_PENALTY * POPCOUNT(friends); + + /* backwards */ + friends = everybodyelse & bb_adjacentcols[COL(square)]; + /* get a mask of all squares behind/same rank as this square */ + if (color == WHITE) + { + behindmask = (BB_SQUARE(square) ^ (BB_SQUARE(square) - 1)) | + BB_RANK(ROW(square)); + } + else + { + behindmask = (BB_SQUARE(square) ^ (-BB_SQUARE(square))) | + BB_RANK(ROW(square)); + } + if (!(friends & behindmask)) + { + value -= PS_BACKWARD_PENALTY; + /* see if isolated entirely */ + if (!friends) /* SO RONERY */ + { + value -= PS_ISOLATED_PENALTY; + } + } + /* calculate holes in pawnstructure - any squares that this + * pawn may be able to attack, take out of the bitmap */ + holes ^= (bb_passedpawnmask[color][square] & ~BB_FILE(COL(square))); + } + ps_add(pawns, holes, value); + *h = holes; + return value + unhashable_bonus; +} +/**************************************************************************** + * popcnt.c - various population-count implementations + * copyright (C) 2008 Ben Blum + ****************************************************************************/ + +/** + * Kernighan's LSB-resetting popcount implementation + */ +int popcnt(uint64_t x) +{ + int count = 0; + while (x) + { + count++; + x &= x - 1; // reset LS1B + } + return count; +} + +/** + * Good on procs with slow multiplication + */ +int popcnt2(uint64_t x) +{ + x -= (x >> 1) & 0x5555555555555555ull; + x = (x & 0x3333333333333333ull) + ((x >> 2) & 0x3333333333333333ull); + x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0full; + x += x >> 8; + x += x >> 16; + x += x >> 32; + return x & 0x7f; +} + +/** + * Good on procs with fast multiplication + */ +int popcnt3(uint64_t x) { + x -= (x >> 1) & 0x5555555555555555ull; + x = (x & 0x3333333333333333ull) + ((x >> 2) & 0x3333333333333333ull); + x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0full; + return (x * 0x0101010101010101ull)>>56; +} +/**************************************************************************** + * quiescent.c - captures-only search to avoid evaluating unstable positions + * copyright (C) 2008 Ben Blum + ****************************************************************************/ + +extern volatile unsigned char timeup; +extern int lazy, nonlazy; + +#ifndef QUIESCENT_MAX_DEPTH +/* Warning: NEVER put this at 4 or below - it causes the bot to be too weak */ +#define QUIESCENT_MAX_DEPTH 8 +#endif + +static int16_t qalphabeta(board_t *, int16_t, int16_t, uint8_t); + +/** + * Play out capture chains in a position until it's quiet (or until a certain + * depth is reached, for speed) so we can accurately use the evaluator + */ +int16_t quiesce(board_t *board, int16_t alpha, int16_t beta) +{ + return qalphabeta(board, alpha, beta, QUIESCENT_MAX_DEPTH); +} + +/** + * Alpha beta searching over captures. Don't need to return a move, only the + * value. No repetition/50-move checking (obvious reasons), no transposition + * table (simplicity) - we get pretty good move ordering for captures already + * from the board library. + */ +static int16_t qalphabeta(board_t *board, int16_t alpha, int16_t beta, + uint8_t depth) +{ + movelist_t moves; + move_t curmove; + /* who has the move */ + int color; + //XXX: due to we're only generating captures, we can't check if we get + //XXX: mated here... this seems bad, but should turn out ok (i.e., a + //XXX: quiescence that doesn't see mates is better than no quiescence + //XXX: at all. + + /* used in place of lastval */ + int16_t a; + + /* what happens if the player to move declines to make any captures */ + int16_t stand_pat; + + if (timeup) + { + return 0; + } + + /* we'll be using stand_pat in a lot of places*/ + /* first do a lazy evaluation; if it's too far from the window we will + * not need the precision of eval() */ + stand_pat = eval_lazy(board); + /* check if we're not allowed to be lazy */ + if ((stand_pat > (alpha - EVAL_LAZY_THRESHHOLD)) && + (stand_pat < (beta + EVAL_LAZY_THRESHHOLD))) + { + stand_pat = eval(board); + nonlazy++; + } + else { lazy++; } + + /******************************************************************** + * terminal condition - search depth ran out + ********************************************************************/ + if (depth == 0) + { + return stand_pat; + } + + /******************************************************************** + * Main iteration over all the moves + ********************************************************************/ + /* set some preliminary values */ + if (stand_pat > alpha) + { + if (stand_pat >= beta) + { + return stand_pat; + } + alpha = stand_pat; + } + color = board->tomove; + + /* and we're ready to go */ + board_generatecaptures(board, &moves); + while (!movelist_isempty(&moves)) + { + if (timeup) + { + break; + } + curmove = movelist_remove_max(&moves); + + board_applymove(board, curmove); + /* see if this move puts us in check */ + if (board_colorincheck(board, color)) + { + board_undomove(board, curmove); + continue; + } + a = -qalphabeta(board, -beta, -alpha, depth-1); + board_undomove(board, curmove); + + if (a > alpha) + { + alpha = a; + } + if (beta <= alpha) + { + break; + } + } + movelist_destroy(&moves); + + return alpha; /* will work even if no captures were available */ +} +/**************************************************************************** + * rand.c - wrappers for GSL random number generation utilities + * copyright (C) 2008 Ben Blum + ****************************************************************************/ + +uint32_t +rand32(void) +{ + rand_init(); + return genrand(); +} + +static unsigned char rand_initted = 0; + +void rand_init() +{ + if (rand_initted) + { + return; + } + sgenrand(get_ticks()); + rand_initted = 1; +} + +uint64_t rand64() +{ + return ((uint64_t)rand32()) | (((uint64_t)rand32()) << 32); +} + +/**************************************************************************** + * search.c - traverse the game tree looking for the best position + * copyright (C) 2008 Ben Blum + ****************************************************************************/ + +/* Constants for the search algorithm */ +#define SEARCHER_INFINITY 32767 +#define SEARCHER_MATE 16383 + +/* could be changed if you wanted to {dis,en}courage draws + * TODO: make the evaluator also use this */ +#define SEARCHER_DRAW_SCORE 0 +#define VALUE_ISDRAW(v) ((v) == SEARCHER_DRAW_SCORE) + +static move_t alphabeta(board_t *, int16_t, int16_t, uint8_t, uint8_t, move_t, uint8_t, uint8_t, unsigned char); + +int transposition_hits, transposition_misses; +extern int regen_hits, regen_misses; + +static int nodes; +static int16_t lastval; + +/* used for printing stuff */ +extern int outbuf_size; +extern int text_loud; +extern char outbuf[]; +void output(); + +/* Used for iterative deepening and replacement policy in the trans table */ +static uint8_t cur_searching_depth; + +/* used for iterative deepening */ +volatile unsigned char timeup; + +#define SEARCHER_MIN_DEPTH 2 +#define SEARCHER_MAX_DEPTH 64 +// configurable; must never get bigger than MAX_DEPTH-1 +unsigned int searcher_max_depth = SEARCHER_MAX_DEPTH-1; + +#define VALUE_ISMATE(v) (((v) >= SEARCHER_MATE - SEARCHER_MAX_DEPTH) || ((v) <= -(SEARCHER_MATE - SEARCHER_MAX_DEPTH))) + +/* aspiration windows - first try a window of aspir_1 around prevalpha; if + * that fails go to aspir_2; if that fails use the full -inf,+inf search */ +#define SEARCHER_ASPIRATION_1 50 +#define SEARCHER_ASPIRATION_2 200 + +/* killer moves + * + * Tried at each move after the hashed bestmove, before generatemoves(). A + * killer move is basically any move by one player that produces a beta cutoff + * when the pther player makes a move from X position; the hope here is that + * the same refutation move will produce a cutoff in the next children of X. + * This is likely to happen if the first player is threatened somehow, and the + * killer will be the followthrough on that threat if player one doesn't + * respond to it. + * + * note - you will want to clear all the killers in the following cases: + * 1) Beginning/end of getbestmove - clear all depths + * 2) After a node finishes its children, clear the nodes at that + * child's ply + * If the killers are not adequately cleared, you may end up applying some + * illegal moves at other nodes, resulting in inconsistent board state. + * Another thing to watch out for is some killers can still be illegal - most + * cases are eliminated by preventing captures and castles, the rest need + * checking against board_attacksfrom() (or pushes, in the case of pawns). + */ +#define SEARCHER_USE_KILLERS +#ifdef SEARCHER_USE_KILLERS +#define SEARCHER_NUM_KILLERS 3 +static move_t killers[SEARCHER_MAX_DEPTH][SEARCHER_NUM_KILLERS]; +#endif + +/* margins for futility pruning - how far away from the window do we need + * to be in order to consider doing futility pruning. note that the value at + * 0 will never be used */ +#ifdef SEARCHER_FUTILITY_PRUNING +static int16_t futility_margin[3] = { 0xbeef, 250, 450 }; +#endif + +int lazy, nonlazy; + +/* determining the type of a child from a parent (first index - parent's type) + * given whether the first child (0 or 1, second index) has been searched */ +#define PV 0 +#define CUT 1 +#define ALL 2 +static unsigned char childnodetype[3][2] = { + /* first child already searched: + * NO YES */ + { PV, CUT }, /* parent was PV */ + { ALL, CUT }, /* parent was CUT */ + { CUT, CUT } /* parent was ALL */ +}; + +/* null-move depth reduction - dependent on depth */ +#define NULLMOVE_R(d) (((d) > 6) ? 3 : 2) + +/* Late move reduction - we reduce after searching this many nodes given the + * current node type (allows us to be more conservative at PV nodes) */ +static uint8_t lmr_movecount[3] = { 16, 8, 8 }; + +#define GUESS_KERNEL_HZ 100 // I really wish the syscall interface exposed this. + +void *sigalrm_thread(void *arg) +{ + sleep((int)arg * GUESS_KERNEL_HZ); + timeup = 1; + return (void *)0x15410FA1L; +} + +/** + * Stores the nodecount in the given int pointer if it's nonnull and the alpha + * value in the second pointer if that's nonnull. + */ +move_t getbestmove(board_t *board, unsigned int time, int *nodecnt, int16_t *alphaval) +{ + move_t result, prevresult; + int16_t prevalpha; + int16_t window_low, window_high; + char *movestr; + int ret; + void *statusp; + + /******************************************************************** + * Setup + ********************************************************************/ + nodes = 0; + timeup = 0; + + transposition_hits = 0; transposition_misses = 0; + regen_hits = 0; regen_misses = 0; + + lazy = 0; nonlazy = 0; + + #ifdef SEARCHER_USE_KILLERS + /* clear all killers */ + memset(killers, 0, sizeof(killers)); + #endif + /******************************************************************** + * Searching + ********************************************************************/ + snprintf(outbuf, outbuf_size, "Thinking (for %d %s)...", + time, time == 1 ? "sec" : "secs"); + output(); + /* preliminary search */ + cur_searching_depth = SEARCHER_MIN_DEPTH; + result = alphabeta(board, -SEARCHER_INFINITY, SEARCHER_INFINITY, + cur_searching_depth, 0, 0, 0, 0, PV); + prevresult = result; + prevalpha = lastval; + + /* start the iterative timer */ + ret = thr_create(sigalrm_thread, (void *)time); + assert(ret > 0 && "Failed to create timer thread"); + + while (!timeup && cur_searching_depth < searcher_max_depth) + { + /* These guys store the result of the previous depth in case + * our next search times up */ + prevresult = result; + prevalpha = lastval; + + // Don't waste time if we have a mate + /*if (lastval >= SEARCHER_MATE) + { + break; + }*/ + + //TODO: Check if we've used up enough time to not even bother with the next search + + /* advance to the next depth */ + movestr = move_tostring(result); + if (text_loud) { + snprintf(outbuf, outbuf_size, "[depth %d] best %s score %d", + cur_searching_depth, movestr, lastval); + output(); + } + if (VALUE_ISMATE(lastval) && text_loud) + { + snprintf(outbuf, outbuf_size, "%s mates in %d", + ((lastval > 0) ? + ((board->tomove == WHITE) ? "White" : "Black") + : + ((board->tomove == WHITE) ? "Black" : "White")), + ((lastval > 0) ? + ((SEARCHER_MATE - lastval + 1) / 2) + : + ((SEARCHER_MATE + lastval + 1) / 2))); + output(); + } + free(movestr); + cur_searching_depth++; + nodes = 0; + + window_low = prevalpha - SEARCHER_ASPIRATION_1; + window_high = prevalpha + SEARCHER_ASPIRATION_1; + result = alphabeta(board, window_low, window_high, + cur_searching_depth, 0, 0, 0, 0, PV); + if (timeup) break; + /* test if aspir_1 window failed */ + if (lastval <= window_low || lastval >= window_high) + { + /* try wider window */ + window_low = prevalpha - SEARCHER_ASPIRATION_2; + window_high = prevalpha + SEARCHER_ASPIRATION_2; + /* re-search */ + result = alphabeta(board, window_low, window_high, + cur_searching_depth, 0, 0, 0, 0, PV); + } + if (timeup) break; + /* test if aspir_2 window failed */ + if (lastval <= window_low || lastval >= window_high) + { + /* use full window */ + window_low = -SEARCHER_INFINITY; + window_high = SEARCHER_INFINITY; + /* re-search */ + result = alphabeta(board, window_low, window_high, + cur_searching_depth, 0, 0, 0, 0, PV); + } + } + + /******************************************************************** + * Teardown + ********************************************************************/ + movestr = move_tostring(prevresult); + if (text_loud) { + if (timeup) { + snprintf(outbuf, outbuf_size, "[depth %d] (timeout, %d nodes)", + cur_searching_depth, nodes); + } else { + snprintf(outbuf, outbuf_size, "[depth %d] best %s score %d", + cur_searching_depth, movestr, lastval); + } + output(); + } + snprintf(outbuf, outbuf_size, "My move: %s", movestr); + output(); + free(movestr); + #ifdef SEARCHER_USE_KILLERS + /* clear killers, just in case */ + memset(killers, 0, sizeof(killers)); + #endif + if (nodecnt != NULL) + { + *nodecnt = nodes; + } + if (alphaval != NULL) + { + *alphaval = prevalpha; + } + // TODO: Do this in a non-blocking way all the time. + thr_join(ret, &statusp); + assert(statusp == (void*)0x15410FA1L); + return prevresult; +} + +/** + * Alpha-beta search, with trans table, check extension, futility pruning + * board - the current node's position + * alpha - lower bound + * beta - upper bound + * depth - how deep we will search this node + * ply - how far this position is from the board's real position (used + * because depth can change based on extensions/reductions) + * prevmove - the move that was just made (used in futility pruning) + * num_checks - how many checks have occurred so far in the search (used for + * check extension) + * nodetype - what type of node we're searching - PV, CUT, or ALL + */ +static move_t alphabeta(board_t *board, int16_t alpha, int16_t beta, + uint8_t depth, uint8_t ply, move_t prevmove, + uint8_t num_checks, uint8_t null_extended, + unsigned char nodetype) +{ + movelist_t moves; + move_t curmove, returnmove; + /* who has the move */ + int color; + /* used for telling if the movelist we got had no non-suicide moves, + * also for telling what the child's node type will be */ + unsigned char children_searched; + + /* transposition table */ + trans_data_t trans_data; + int trans_flag; + /* for move ordering */ + move_t bestmove; + + int killer_index; + + nodes++; + if (timeup) + { + return 0; + } + /******************************************************************** + * threefold repetition/50 move - always check first + ********************************************************************/ + /* draw score if only even -one- prior repetition, not two. this is + * more efficient (taken from crafty). note that it obsoletes storing + * the repetition count in the trans table, but if it gets put back, + * transing the reps will still be essential. */ + if (board->halfmoves >= 100 || board_threefold_draw(board)) + { + //fprintf(ttyout, "%sSEARCHER: Detected threefold repetition at depth %d%s\n", + // TTYOUT_COLOR, cur_searching_depth - depth, DEFAULT_COLOR); + lastval = SEARCHER_DRAW_SCORE; + return 0; + } + /******************************************************************** + * check transposition table + ********************************************************************/ + trans_data = trans_get(board->hash); + if (trans_data_valid(trans_data)) + { + if (TRANS_SEARCHDEPTH(trans_data) >= depth && + TRANS_REPS(trans_data) >= board->reps) + { + int16_t storedval = TRANS_VALUE(trans_data); + + /* direct hit! */ + if (TRANS_FLAG(trans_data) == TRANS_FLAG_EXACT) + { + transposition_hits++; + lastval = storedval; + return TRANS_MOVE(trans_data); + } + /* if we do this on the root node, we run the risk of + * getting a1a1 as the returnmove, so prevent it */ + else if (depth != cur_searching_depth) + { + /* we have a lower bound for the true value */ + if (TRANS_FLAG(trans_data) == TRANS_FLAG_BETA) + { + /* above our current window? */ + if (storedval >= beta) + { + transposition_hits++; + lastval = storedval; + return 0; + } + /* not above the window but inside? */ + if (storedval > alpha) + { + alpha = storedval; + } + } + /* this means we'll have an upper bound */ + else if (TRANS_FLAG(trans_data) == + TRANS_FLAG_ALPHA) + { + /* below current window entirely? */ + if (storedval <= alpha) + { + transposition_hits++; + lastval = storedval; + return 0; + } + /* inside window - cut the top off */ + if (storedval < beta) + { + beta = storedval; + } + } + } + } + /* well, we can still use move-ordering information. note: + * we'll want to grab it regardless of the flag. if it's beta + * we'll get a move; if it's alpha we'll get 0; oh well */ + bestmove = TRANS_MOVE(trans_data); + } + else + { + bestmove = (move_t)0; + transposition_misses++; + } + /******************************************************************** + * terminal condition - search depth ran out + * futility pruning done here + ********************************************************************/ + if (depth == 0) + { + lastval = quiesce(board, alpha, beta); + /* we time up in the middle of quiescence and get zero, and go + * to add it in the trans table, OH SHI-- */ + if (timeup) + { + return 0; + } + /* if we already have an entry, and this is an end condition, + * we don't want to replace our better entry */ + if (!trans_data_valid(trans_data)) + { + trans_add(board->hash, (move_t)0, board->reps, lastval, + (board->moves - cur_searching_depth), + board->moves, 0, TRANS_FLAG_EXACT); + } + return 0; + } + #ifdef SEARCHER_FUTILITY_PRUNING + /* futility pruning - prune only 1 and 2 plies from the horizon */ + else if (depth < 3) + { + /* if we're in check or possibly in a capture sequence, trying + * to prune will be too dangerous */ + if (!(board_incheck(board) || MOV_CAPT(prevmove))) + { + int16_t score = eval_lazy(board); + /* check how far we are from the window */ + if ((score + futility_margin[depth] < alpha) || + (score - futility_margin[depth] > beta)) + { + lastval = quiesce(board, alpha, beta); + return 0; + } + } + } + #endif + /******************************************************************** + * Null-move pruning + ********************************************************************/ + /* only do it if all of the following: + * we're a fail-high (CUT) node + * depth is not three or less + * we're not in the endgame + * a lazy eval fails high + * we're not in check + */ + if ((nodetype != PV) && (depth > 3) && !eval_isendgame(board) && + (eval_lazy(board) >= beta) && !board_incheck(board)) + { + /* make null move */ + board_applymove(board, 0); + alphabeta(board, -beta, -beta+1, depth - NULLMOVE_R(depth) - 1, + ply+1, 0, num_checks, null_extended, ALL); + board_undomove(board, 0); + + /* failed high, we can prune */ + if (-lastval >= beta) + { + lastval = -lastval; + return 0; + } + /* mate threat - if we do nothing here, we get mated. better + * search deeper. only extend this way once per line. */ + if (VALUE_ISMATE(lastval) && !null_extended) + { + depth++; + null_extended = 1; + } + } + /******************************************************************** + * Main iteration over all the moves + ********************************************************************/ + /* set some preliminary values */ + color = board->tomove; + children_searched = 0; + returnmove = 0; + trans_flag = TRANS_FLAG_ALPHA; + /* and we're ready to go - first do hash move and killers */ + if (bestmove) + { + board_applymove(board, bestmove); + /* if this puts us in check something's really wrong... */ + assert(!board_colorincheck(board, color)); + /* check extension - if this checks the opp king */ + if (board_incheck(board)) + { + /* only extend search if >1 checks in tree */ + if (num_checks) + { + alphabeta(board, -beta, -alpha, depth, ply+1, + bestmove, num_checks+1, null_extended, + childnodetype[nodetype][!!children_searched]); + } + else + { + alphabeta(board, -beta, -alpha, depth-1, ply+1, + bestmove, num_checks+1, null_extended, + childnodetype[nodetype][!!children_searched]); + } + } + else /* no extensions, regular search */ + { + alphabeta(board, -beta, -alpha, depth-1, ply+1, + bestmove, num_checks, null_extended, + childnodetype[nodetype][!!children_searched]); + } + board_undomove(board, bestmove); + children_searched++; + + if (-lastval > alpha) + { + alpha = -lastval; + returnmove = bestmove; + trans_flag = TRANS_FLAG_EXACT; + } + if (alpha >= beta) + { + trans_flag = TRANS_FLAG_BETA; + goto alphabeta_after_iteration; + } + } + #ifdef SEARCHER_USE_KILLERS + /* no cutoff from the bestmove (or no bestmove); let's try killers */ + for (killer_index = 0; killer_index < SEARCHER_NUM_KILLERS; killer_index++) + { + move_t killer = killers[ply][killer_index]; + piece_t killerpiece; + square_t killersrc, killerdest; + /* check if a killer is available */ + if (killer == 0 || timeup) + { + break; + } + killerpiece = MOV_PIECE(killer); + killersrc = MOV_SRC(killer); + killerdest = MOV_DEST(killer); + /* need to check if the killer is legal in this position; it's + * guaranteed to not be a capture or castle, so the following + * legality checks are made: + * 1) We have the given piece on that square + * 2) The destination square is not occupied (by either color) + * 3) If a sliding piece, there must be nothing in the way */ + if ((!(BB_SQUARE(killersrc) & board->pos[color][killerpiece])) || + (BB_SQUARE(killerdest) & board->occupied) || /* #2 */ + (PIECE_SLIDES(killerpiece) && /* #3 */ + !(BB_SQUARE(killerdest) & + board_attacksfrom(board, killersrc, killerpiece, color)))) + { + continue; + } + /* next we check if our piece can move to the destsquare */ + if (killerpiece == PAWN) + { + /* destination square not among the legal pushes? */ + if (!(BB_SQUARE(killerdest) & + board_pawnpushesfrom(board, killersrc, color))) + { + continue; + } + } + else + { + /* destination square not among the legal moves? */ + if (!(BB_SQUARE(killerdest) & + board_attacksfrom(board, killersrc, killerpiece, + color))) + { + continue; + } + } + /* we have a pseudolegal killer move to try, good */ + board_applymove(board, killer); + /* this might put us in check, unlike the bestmove */ + if (board_colorincheck(board, color)) + { + board_undomove(board, killer); + continue; + } + /* check extension - if this checks the opp king */ + if (board_incheck(board)) + { + /* only extend search if >1 checks in tree */ + if (num_checks) + { + alphabeta(board, -beta, -alpha, depth, ply+1, + killer, num_checks+1, null_extended, + childnodetype[nodetype][!!children_searched]); + } + else + { + alphabeta(board, -beta, -alpha, depth-1, ply+1, + killer, num_checks+1, null_extended, + childnodetype[nodetype][!!children_searched]); + } + } + else /* no extensions, regular search */ + { + alphabeta(board, -beta, -alpha, depth-1, ply+1, + killer, num_checks, null_extended, + childnodetype[nodetype][!!children_searched]); + } + board_undomove(board, killer); + children_searched++; + + if (-lastval > alpha) + { + alpha = -lastval; + returnmove = killer; + trans_flag = TRANS_FLAG_EXACT; + } + if (alpha >= beta) + { + trans_flag = TRANS_FLAG_BETA; + goto alphabeta_after_iteration; + } + } + #endif + /* okay, no beta cutoff; let's continue... */ + board_generatemoves(board, &moves); + while (!movelist_isempty(&moves)) + { + if (timeup) + { + break; + } + curmove = movelist_remove_max(&moves); + + board_applymove(board, curmove); + /* see if this move puts us in check */ + if (board_colorincheck(board, color)) + { + board_undomove(board, curmove); + continue; + } + /* check extension - if this checks the opp king */ + if (board_incheck(board)) + { + /* only extend search if >1 checks in tree */ + if (num_checks) + { + alphabeta(board, -beta, -alpha, depth, ply+1, + curmove, num_checks+1, null_extended, + childnodetype[nodetype][!!children_searched]); + } + else + { + alphabeta(board, -beta, -alpha, depth-1, ply+1, + curmove, num_checks+1, null_extended, + childnodetype[nodetype][!!children_searched]); + } + } + /* Late move reductions (LMR) + * The idea here is if a move occurs late in the movelist, + * it's probably not worth searching to a full depth (if it + * happens to return a value within the window, re-search with + * full depth). This works recursively, so strings of moves + * that are all Late get searched to (optimal case) 1/2 depth + * overall, while lines with just one Late move are searched + * with depth reduced by just one overall. What happens if we + * encounter a seemingly bad move that only pays off when + * searched to the full depth (i.e. sacrifice -> attack)? + * Typically, such lines will only have one or two Late moves + * in them, and we rely on the more extreme reductions on the + * completely nonsense lines (1/2-depth mentioned before) to + * possibly give us another ply so we find the sacrifice. */ + else if (children_searched > lmr_movecount[nodetype] && depth > 3 && + !MOV_CAPT(curmove) && !MOV_CAPT(prevmove)) + { + alphabeta(board, -beta, -alpha, depth-2, ply+1, + curmove, num_checks, null_extended, + childnodetype[nodetype][1]); + /* oops, it fell within our window. full re-search */ + if (-lastval > alpha) + { + alphabeta(board, -beta, -alpha, depth-1, ply+1, + curmove, num_checks, null_extended, + childnodetype[nodetype][1]); + } + } + else /* no extensions/reductions, regular search */ + { + alphabeta(board, -beta, -alpha, depth-1, ply+1, + curmove, num_checks, null_extended, + childnodetype[nodetype][!!children_searched]); + } + board_undomove(board, curmove); + children_searched++; + + if (-lastval > alpha) + { + alpha = -lastval; + returnmove = curmove; + /* we've gotten above the bottom of the window */ + trans_flag = TRANS_FLAG_EXACT; + } + if (beta <= alpha) + { + /* oops, above the top of the window */ + trans_flag = TRANS_FLAG_BETA; + #ifdef SEARCHER_USE_KILLERS + /* Not a killer if capture or castle */ + if (!(MOV_CAPT(curmove)) && !(MOV_CASTLE(curmove))) + { + /* We found a killer move! Add it in... note + * we will never here cause duplicate killers + * because we would have tested this killer + * earlier and skipped this */ + killer_index = 0; + while ((killers[ply][killer_index] != 0) && + (killer_index < SEARCHER_NUM_KILLERS-1)) + { + /* move to first empty killer slot, + * or if full replace at the end */ + killer_index++; + } + killers[ply][killer_index] = curmove; + } + #endif + break; + } + } + movelist_destroy(&moves); + /* now we are done iterating; cleanup and exit this node. note, this + * label is here so we can skip over iteration if the bestmove/killers + * produce a cutoff */ +alphabeta_after_iteration: + /* The transposition table will get really sad if we choke all over it + * with bogus results from after we get cut off */ + if (timeup) + { + return 0; + } + #ifdef SEARCHER_USE_KILLERS + /* okay we need to clear the killers for the children here */ + memset(killers[ply+1], 0, (SEARCHER_NUM_KILLERS * sizeof(move_t))); + #endif + /* check if there were no legal moves */ + if (children_searched) + { + /* this is the "typical case" function ending + * set the value so the calling function sees it properly */ + lastval = alpha; + /* Don't add mates because they are depth-dependent. Don't add + * draws because they are state-dependent. */ + if (!VALUE_ISMATE(alpha) && !VALUE_ISDRAW(alpha)) + { + /* update the trans table - here we always replace */ + trans_add(board->hash, returnmove, board->reps, alpha, + (board->moves + depth - cur_searching_depth), + board->moves, depth, trans_flag); + } + } + else /* no children were searched - must be an end condition */ + { + /* checkmate vs stalemate */ + if (board_incheck(board)) + { + lastval = -1 * (SEARCHER_MATE - ply); + } + else + { + lastval = 0; + } + /* DON'T add to the transposition table here... this can screw + * up which mates are sooner and cause 3-rep draws - besides, + * if a mate is coming up and we've seen it there's no use + * trying to search deeper/faster */ + return 0; + } + /* and we're done */ + return returnmove; +} +/**************************************************************************** + * transposition.c - avoid re-searching already searched positions + * copyright (C) 2008 Ben Blum + ****************************************************************************/ + +typedef struct trans_entry_t { + uint64_t key; + trans_data_t value; +} trans_entry_t; + +/** + * Statically initting the array is good because it avoids committing memory + * we don't use, but depends, for efficiency not correctness, on the kernel + * harbl-filling our memory with zeros. When we go to kick out an entry, if + * we haven't put one there yet, we'll see that the depth is 0 and the flag + * is ALPHA - the two worst possible values, so this type will always be + * replaced. + */ +#ifndef TRANS_NUM_BUCKETS +#define TRANS_NUM_BUCKETS ((128 * 1024 * 1024)/sizeof(trans_entry_t)) // 128 MB +#endif +static trans_entry_t array[TRANS_NUM_BUCKETS]; + +/** + * Convert separate data values -> condensed struct + */ +static trans_data_t trans_data(move_t move, uint8_t reps, int16_t value, + uint8_t gamedepth, uint8_t searchdepth, + uint8_t flag) +{ + trans_data_t foo; + assert(searchdepth < 64); + foo.move = move | (reps << MOV_INDEX_UNUSED); + foo.value = value; + foo.gamedepth = gamedepth; + foo.flags = ((searchdepth & 0x3f) << TRANS_INDEX_SEARCHDEPTH) | + ((flag & 0x3) << TRANS_INDEX_FLAG); + return foo; +} + +/** + * Add transposition information to the table. Note, it will only kick the old + * entry out if: + * 1) The flag is higher (exact kicks out beta, beta kicks out alpha) + * 2) The flag is equal and the depth is higher + * 3) The old node was from ancient history + * Note the different depth arguments: + * rootdepth - how far down the game tree the real board state is. + * used in comparison for evicting the old node. + * gamedepth - how far down this current node is in the game tree. we + * store this for future nodes to use to evict us. + * searchdepth - how much deeper still we've searched this node. this + * tells how trustworthy the alpha value is. + * At present we don't discriminate based on repetition depth. + */ +void trans_add(zobrist_t key, move_t move, uint8_t reps, int16_t value, + uint8_t rootdepth, uint8_t gamedepth, + uint8_t searchdepth, uint8_t flag) +{ + unsigned long bucket; + trans_data_t old; + + /* find the bucket */ + bucket = key % TRANS_NUM_BUCKETS; + + /* find what used to be there */ + old = array[bucket].value; + + /* see if we should evict */ + if ((rootdepth >= TRANS_GAMEDEPTH(old)) || /* old node too old */ + (flag > TRANS_FLAG(old)) || /* more accurate data */ + ((flag == TRANS_FLAG(old)) && /* same type of data but... */ + (searchdepth > TRANS_SEARCHDEPTH(old)))) /* ...deeper search */ + { + /* so we set the stuff to our new node */ + array[bucket].key = key; + array[bucket].value = trans_data(move, reps, value, gamedepth, + searchdepth, flag); + } + return; +} + +/** + * Fetch data from the table. If there is no entry for this key the flag in + * the return value will be set to -1. + */ +static trans_data_t foo = { (uint8_t)(-1), (uint8_t)(-1), + (int16_t)(-1), (uint32_t)(-1) }; +trans_data_t trans_get(zobrist_t key) +{ + unsigned long bucket = key % TRANS_NUM_BUCKETS; + if (array[bucket].key == key) + { + return array[bucket].value; + } + return foo; +} + +/** + * Check if the transposition data is valid, according to whatever spec may be + * in use for saying "invalid entry". Used for checking the returnvalue of get + */ +int trans_data_valid(trans_data_t foo) +{ + return (foo.flags != (uint8_t)(-1)); +} + +/****************************************************************************** + * Custom pebbles interface + ******************************************************************************/ + +/********************** BOARD / SCREEN CONTENT ********************************/ + +char *board_strs[] = { + " a b c d e f g h ", + " .-------------------------------. ", + "8 | | | | | | | | | 8", + " |---+---+---+---+---+---+---+---| ", + "7 | | | | | | | | | 7", + " |---+---+---+---+---+---+---+---| ", + "6 | | | | | | | | | 6", + " |---+---+---+---+---+---+---+---| ", + "5 | | | | | | | | | 5", + " |---+---+---+---+---+---+---+---| ", + "4 | | | | | | | | | 4", + " |---+---+---+---+---+---+---+---| ", + "3 | | | | | | | | | 3", + " |---+---+---+---+---+---+---+---| ", + "2 | | | | | | | | | 2", + " |---+---+---+---+---+---+---+---| ", + "1 | | | | | | | | | 1", + " `-------------------------------' ", + " a b c d e f g h ", +}; +char *board_strs_flipped[] = { + " h g f e d c b a ", + " .-------------------------------. ", + "1 | | | | | | | | | 1", + " |---+---+---+---+---+---+---+---| ", + "2 | | | | | | | | | 2", + " |---+---+---+---+---+---+---+---| ", + "3 | | | | | | | | | 3", + " |---+---+---+---+---+---+---+---| ", + "4 | | | | | | | | | 4", + " |---+---+---+---+---+---+---+---| ", + "5 | | | | | | | | | 5", + " |---+---+---+---+---+---+---+---| ", + "6 | | | | | | | | | 6", + " |---+---+---+---+---+---+---+---| ", + "7 | | | | | | | | | 7", + " |---+---+---+---+---+---+---+---| ", + "8 | | | | | | | | | 8", + " `-------------------------------' ", + " h g f e d c b a ", +}; +#define BOARD_ROW 3 // the row of the opponent's sides lettering (a-h/h-a) +#define BOARD_COL 4 // the col of the left side numbering (1-8/8-1) +#define BOARD_ROW_SCALE 2 +#define BOARD_COL_SCALE 4 + +#define BOARD_COLOR (FGND_BRWN | BGND_BLACK) +#define WHITE_COLOR (FGND_WHITE | BGND_BLACK) +#define BLACK_COLOR (FGND_RED | BGND_BLACK) // like the old-time chess sets + +int flipped = 0; +int xyzzy = 0; + +void set_text_color(int color) { + int low = color & 0xf; + int high = color & ~0xf; + if (low == FGND_BLACK) { + set_term_color(color); + } else { + low = (low + xyzzy) & 0xf; + if (low == FGND_BLACK) low++; + set_term_color(low | high); + } +} + +void draw_pieces(board_t *board, int color) { + int square; + bitboard_t pos; + int piece = PAWN; + while (piece <= KING) { + pos = board->pos[color][piece]; + while (pos) { + int row_offset, col_offset; + square = BITSCAN(pos); + if (flipped) { + row_offset = BOARD_ROW_SCALE*(1 + ROW(square)); + col_offset = BOARD_COL_SCALE*(8 - COL(square)); + } else { + row_offset = BOARD_ROW_SCALE*(8 - ROW(square)); + col_offset = BOARD_COL_SCALE*(1 + COL(square)); + } + set_cursor_pos(BOARD_ROW + row_offset, BOARD_COL + col_offset); + print(1, piecename[color][piece]); + pos &= BB_ALLEXCEPT(square); + } + piece++; + } +} + +// I'd say this should be called only on redraw, but it also has the +// convenient effect of setting blank all unoccupied squares, which means +// fewer syscalls overall... unless you'd like to analyse the board state +// to determine what the most recently vacated square is.... etc. +void draw_board(board_t *board) { + unsigned int i; + set_text_color(BOARD_COLOR); + if (flipped) { + for (i = 0; i < ARRAY_SIZE(board_strs_flipped); i++) { + set_cursor_pos(BOARD_ROW+i, BOARD_COL); + print(strlen(board_strs_flipped[i]), board_strs_flipped[i]); + } + } else { + for (i = 0; i < ARRAY_SIZE(board_strs); i++) { + set_cursor_pos(BOARD_ROW+i, BOARD_COL); + print(strlen(board_strs[i]), board_strs[i]); + } + } + set_text_color(WHITE_COLOR); + draw_pieces(board, WHITE); + set_text_color(BLACK_COLOR); + draw_pieces(board, BLACK); +} + +enum player_mode { + bot_black = 0, + bot_white = 1, + human = 2, +}; +char *player_strs[] = { + "you vs bistromath", + "bistromath vs you", + " you vs yourself ", +}; +#define PLAYERSTR_ROW 1 +#define PLAYERSTR_COL 14 +#define PLAYERSTR_COLOR (FGND_BBLUE | BGND_BLACK) + +enum player_mode player_mode = bot_black; + +void draw_player_str() { + set_text_color(PLAYERSTR_COLOR); + set_cursor_pos(PLAYERSTR_ROW, PLAYERSTR_COL); + assert(player_mode < ARRAY_SIZE(player_strs)); + print(strlen(player_strs[player_mode]), + player_strs[player_mode]); +} + +#define STATUS_WHITEMOVE " [white to move] " +#define STATUS_BLACKMOVE " [black to move] " +#define STATUS_WHITEMATE " [0-1 white checkmated] " +#define STATUS_BLACKMATE " [1-0 black checkmated] " +#define STATUS_WHITERESIGN " [0-1 white resigns] " +#define STATUS_BLACKRESIGN " [1-0 black resigns] " +#define STATUS_DRAW3MOVE " [1/2-1/2 game drawn by 3-fold repetition] " +#define STATUS_DRAW50MOVE " [1/2-1/2 game drawn by 50 move rule] " +#define STATUS_DRAWSTALE " [1/2-1/2 game drawn by stalemate] " +#define STATUS_DRAWNOMATE "[1/2-1/2 neither side has mating material]" + +#define STATUS_ROW 23 +#define STATUS_COL 1 +#define STATUS_COLOR (FGND_BBLUE | BGND_BLACK) + +char *status_str = STATUS_WHITEMOVE; + +// gentleperson's agreement: msg must be one of the predefined ones above +void draw_status_str() { + assert(strlen(status_str) == strlen(STATUS_WHITEMOVE)); + set_text_color(STATUS_COLOR); + set_cursor_pos(STATUS_ROW, STATUS_COL); + print(strlen(status_str), status_str); +} + +/************************* CONSOLE LIBRARY ************************************/ + +char *helptext[] = { + "Commands available: ", + "a2a4 - move (e.g.) ", // + "e7e8Q - move with pawn promote ", // + "go - switch sides; bot goes ", // + "human - let two people play ", // + "flip - turn the board around ", // + "new - start a new game ", // + "quiet - don't think out loud ", // + "loud - think out loud ", // + "hint - what the bot would do ", // + "undo - take back a move ", // + "resign - give up ", // + "depth - set/show difficulty ", // + "time - set search time limit ", + "book - turn on/off opening book", // + "credit - show credit info ", // + "help - show this ", // + "quit - quit ", // + "Sorry no algebraic move syntax. ", +}; + +char *credittext[] = { + "\"Bistromath\" is (C) 2013 Ben Blum", + "Originally written 2008 ", + "Engine finished 2010 ", + "Ported to Pebbles 2012 ", + "Questions/bugs? bblum@cs.cmu.edu", + "(type \"help\" for commands) ", +}; + +#define CONSOLE_HEIGHT 25 +#define CONSOLE_WIDTH 80 + +// these defines could be a little more flexible +#define TEXT_WIDTH 34 // custom console dimensions +#define TEXT_HEIGHT (CONSOLE_HEIGHT-2) +#define TEXT_ROW 0 // where the custom console's top left corner is +#define TEXT_COL (CONSOLE_WIDTH-TEXT_WIDTH) +char textconsole[TEXT_HEIGHT][TEXT_WIDTH]; +#define PROMPT "> " +#define TEXT_COLOR (FGND_GREEN | BGND_BLACK) +#define PROMPT_COLOR (FGND_BGRN | BGND_BLACK) + +void init_console() { + int i, j; + for (i = 0; i < TEXT_HEIGHT; i++) { for (j = 0; j < TEXT_WIDTH; j++) { + textconsole[i][j] = ' '; + }} +} + +// Printing e.g. help text would be more efficient with a print n lines function +// Future work! At least draw_console is separated out. +void print_line(const char *buf, unsigned int len) { + if (len > TEXT_WIDTH) len = TEXT_WIDTH; + /* Scroll. */ + int i; + for (i = 1; i < TEXT_HEIGHT; i++) { + strncpy(textconsole[i-1], textconsole[i], TEXT_WIDTH); + } + /* Command prompt always stays on the bottom. */ + strncpy(textconsole[TEXT_HEIGHT-1], buf, len); + /* Pad rest of line with whitespace */ + for (i = len; i < TEXT_WIDTH; i++) { + textconsole[TEXT_HEIGHT-1][i] = ' '; + } +} + +// Flush, essentially +void draw_console() { + int i; + set_text_color(TEXT_COLOR); + for (i = 0; i < TEXT_HEIGHT; i++) { + set_cursor_pos(TEXT_ROW + i, TEXT_COL); + print(TEXT_WIDTH, textconsole[i]); + } +} +void draw_prompt() { + char buf[TEXT_WIDTH+1]; // Trac ticket #157. ARGGH + set_text_color(PROMPT_COLOR); + set_cursor_pos(TEXT_ROW + TEXT_HEIGHT, TEXT_COL); + assert(strlen(PROMPT) < TEXT_WIDTH); + snprintf(buf, TEXT_WIDTH, "%s%*s", PROMPT, TEXT_WIDTH-strlen(PROMPT), " "); + buf[TEXT_WIDTH-1] = 0; // Trac ticket #157. ARGGH + print(TEXT_WIDTH, buf); + set_cursor_pos(TEXT_ROW + TEXT_HEIGHT, TEXT_COL + strlen(PROMPT)); +} + + +// for other modules of the engine to print +int outbuf_size = TEXT_WIDTH; +char outbuf[TEXT_WIDTH]; +void output() { print_line(outbuf, TEXT_WIDTH); draw_console(); } + +/**************************** MAIN ROUTINES ***********************************/ + +int text_loud = 1; + +void help() { + unsigned int i; + for (i = 0; i < ARRAY_SIZE(helptext); i++) { + print_line(helptext[i], strlen(helptext[i])); + } +} +void credits() { + unsigned int i; + for (i = 0; i < ARRAY_SIZE(credittext); i++) { + print_line(credittext[i], strlen(credittext[i])); + } +} + +void redraw(board_t *board) { + // clear screen + int i; + char spaces[CONSOLE_WIDTH+1]; // Trac ticket #157. ARGGH + snprintf(spaces, CONSOLE_WIDTH, "%*s", CONSOLE_WIDTH, " "); + spaces[CONSOLE_WIDTH-1] = 0; // Trac ticket #157. ARGGH + set_text_color(FGND_BLACK | BGND_BLACK); // erase existing bgnd + for (i = 0; i < CONSOLE_HEIGHT; i++) { + set_cursor_pos(i, 0); + print(CONSOLE_WIDTH, spaces); + } + // draw everything + draw_board(board); + draw_player_str(); + draw_status_str(); + draw_console(); + draw_prompt(); +} + +engine_t *e; +int gameover = 0; + +int checkgameover() { + int matetype; + if (e->board->halfmoves >= 100) { + status_str = STATUS_DRAW50MOVE; + return 1; + } else if (board_threefold_draw(e->board)) { + status_str = STATUS_DRAW3MOVE; + return 1; + } + /* Resignation is handled elsewhere */ + matetype = board_mated(e->board); + /* check if a player is mated */ + if (matetype == BOARD_CHECKMATED) { + status_str = e->board->tomove == WHITE ? STATUS_WHITEMATE + : STATUS_BLACKMATE; + return 1; + } else if (matetype == BOARD_STALEMATED) { + status_str = STATUS_DRAWSTALE; + return 1; + } else if ((e->board->material[BLACK] == 0 && // Both players have 0 + e->board->material[WHITE] == 0) || + (e->board->material[BLACK] == 0 && // B has 0, W has N or B + ((e->board->material[WHITE] == eval_piecevalue[BISHOP] && + e->board->pos[WHITE][BISHOP] != BB(0x0)) || + (e->board->material[WHITE] == eval_piecevalue[KNIGHT] && + e->board->pos[WHITE][KNIGHT] != BB(0x0)))) || + (e->board->material[WHITE] == 0 && // W has 0, B has N or B + ((e->board->material[BLACK] == eval_piecevalue[BISHOP] && + e->board->pos[BLACK][BISHOP] != BB(0x0)) || + (e->board->material[BLACK] == eval_piecevalue[KNIGHT] && + e->board->pos[BLACK][KNIGHT] != BB(0x0))))) { + status_str = STATUS_DRAWNOMATE; + return 1; + } else { + status_str = e->board->tomove == WHITE ? STATUS_WHITEMOVE + : STATUS_BLACKMOVE; + return 0; + } +} + +void makemove() { + draw_prompt(); + // TODO: Spawn a separate thread that can interrupt... somehow? + char *str = engine_generatemove(e); + char *errmsg; + int x = engine_applymove(e, str, &errmsg); + affirm_msg(x, "engine_generatemove() generated an illegal move"); + free(str); +} + +#define INBUF_LEN (2*TEXT_WIDTH) +static inline void print_string(const char *s) { print_line(s, strlen(s)); } + +int main() { + thr_init(4096); + e = engine_init(getbestmove); + char inbuf[INBUF_LEN]; + char *nogame = "No game is in progress."; + assert(e != NULL); + { + int i; + init_console(); + credits(); + for (i = ARRAY_SIZE(credittext); i < TEXT_HEIGHT; i++) { + print_line("", 0); + } + redraw(e->board); + } + while(1) { + int ret, need_redraw = 0; + char inbuf2[TEXT_WIDTH]; + memset(inbuf, 0, sizeof(inbuf)); + ret = readline(INBUF_LEN-1, inbuf); + affirm_msg(ret >= 0, "readline() failed"); + if (inbuf[strlen(inbuf)-1] == '\n') { + inbuf[strlen(inbuf)-1] = '\0'; + } + if (strlen(inbuf) > TEXT_WIDTH-strlen(PROMPT)) { + need_redraw = 1; + snprintf(inbuf + TEXT_WIDTH - strlen(PROMPT) - 3, + 3, "..."); + } + /* echo user command */ + snprintf(inbuf2, TEXT_WIDTH, "%s%s", PROMPT, inbuf); + print_line(inbuf2, strlen(inbuf2)); + /* process command */ + if (0 == strcmp(inbuf, "quit") || 0 == strcmp(inbuf, "exit")) { + set_cursor_pos(CONSOLE_HEIGHT, 0); + engine_destroy(e); + thr_exit(0); + return 0; + /* Misc management */ + } else if (0 == strcmp(inbuf, "help")) { + help(); + } else if (0 == strcmp(inbuf, "credit")) { + credits(); + } else if (0 == strcmp(inbuf, "loud")) { + if (text_loud) { + print_string("This is as loud as I can be!"); + } else { + print_string("Will now think out loud."); + text_loud = 1; + } + } else if (0 == strcmp(inbuf, "quiet")) { + if (!text_loud) { + print_string("You don't need to ask twice."); + } else { + print_string("OK, I'll keep it to myself."); + text_loud = 0; + } + } else if (0 == strcmp(inbuf, "flip")) { + flipped = !flipped; + if (!need_redraw) draw_board(e->board); + } else if (0 == strcmp(inbuf, "book")) { + book_enabled = !book_enabled; + if (book_enabled) { + print_string("Opening book on."); + e->inbook = 1; + } else { + print_string("Opening book off."); + } + /* Easter eggs */ + } else if (0 == strncmp(inbuf, "punch", 5) || + 0 == strncmp(inbuf, "kill", 4)) { + print_string("Keep your mind on the game."); + } else if (0 == strncmp(inbuf, "hug", 3)) { + print_string("If you think that'll help."); + } else if (0 == strncmp(inbuf, "look", 4) || + 0 == strcmp(inbuf, "north") || 0 == strcmp(inbuf, "n") || + 0 == strcmp(inbuf, "east") || 0 == strcmp(inbuf, "e") || + 0 == strcmp(inbuf, "south") || 0 == strcmp(inbuf, "s") || + 0 == strcmp(inbuf, "west") || 0 == strcmp(inbuf, "w")) { + print_string("This isn't that kind of game."); + } else if (0 == strcmp(inbuf, "inventory")) { + print_string("Nothing. This isn't bughouse."); + } else if (0 == strcmp(inbuf, "ls")) { + print_string("I'll pretend you didn't say that."); + } else if (0 == strcmp(inbuf, "xyzzy")) { + xyzzy++; + if (xyzzy == 0x10) xyzzy = 0; + need_redraw = 1; + /* Game management */ + } else if (0 == strcmp(inbuf, "resign")) { + // Future feature: ask "are you sure?" (also on "new") + if (gameover) { + print_string(nogame); + } else { + print_string("I'm sorry it had to be that way."); + gameover = 1; + status_str = e->board->tomove == WHITE ? + STATUS_WHITERESIGN : STATUS_BLACKRESIGN; + draw_status_str(); + } + } else if (0 == strcmp(inbuf, "hint")) { + trans_data_t trans_data = trans_get(e->board->hash); + if (gameover) { + print_string(nogame); + } else if (trans_data_valid(trans_data)) { + char *move = move_tostring(TRANS_MOVE(trans_data)); + static unsigned int hint_index = 0; + const char *words[] = + { "Consider %s.", "Why not %s?", + "How do you feel about %s?", + "If it were me, I'd play %s." }; + snprintf(inbuf2, TEXT_WIDTH, + words[hint_index++ % ARRAY_SIZE(words)], + move); + print_line(inbuf2, strlen(inbuf2)); + free(move); + } else { + print_string("You're on your own here."); + } + } else if (0 == strcmp(inbuf, "new")) { + gameover = 0; + flipped = 0; + player_mode = bot_black; + status_str = STATUS_WHITEMOVE; + engine_destroy(e); + e = engine_init(getbestmove); + assert(e != NULL); + need_redraw = 1; + } else if (0 == strcmp(inbuf, "human")) { + if (gameover) { + print_string(nogame); + } else { + player_mode = human; + if (!need_redraw) draw_player_str(); + } + } else if (0 == strncmp(inbuf, "depth", 5)) { + // See trac bug #73. Argghhhh. + char *endp; + unsigned int n = strtol(&inbuf[6], &endp, 0); + assert(searcher_max_depth < SEARCHER_MAX_DEPTH); + assert(searcher_max_depth >= SEARCHER_MIN_DEPTH); + if (inbuf[5] != ' ' || endp == &inbuf[6]) { + print_string("Use \"depth N\" to limit max depth."); + snprintf(inbuf2, TEXT_WIDTH, "Currently %u (0 = no limit)", + searcher_max_depth == SEARCHER_MAX_DEPTH-1 ? + 0 : searcher_max_depth); + print_string(inbuf2); + } else { + if (n >= SEARCHER_MAX_DEPTH || n == 0) + n = SEARCHER_MAX_DEPTH-1; + else if (n < SEARCHER_MIN_DEPTH) + n = SEARCHER_MIN_DEPTH; + searcher_max_depth = n; + print_string("OK."); + } + } else if (0 == strncmp(inbuf, "time", 4)) { + // Argghhhh, as above. + char *endp; + unsigned int n = strtol(&inbuf[5], &endp, 0); + assert(searchtime >= 1); + assert(searchtime <= SEARCHTIME_MAX); + if (inbuf[4] != ' ' || endp == &inbuf[5]) { + print_string("Use \"time N\" to limit search time."); + snprintf(inbuf2, TEXT_WIDTH, "Currently %u (max %u)", + searchtime, SEARCHTIME_MAX); + print_string(inbuf2); + } else { + if (n > SEARCHTIME_MAX || n == 0) + n = SEARCHTIME_DEFAULT; + searchtime = n; + print_string("OK."); + } + } else if (0 == strcmp(inbuf, "undo")) { + const char *words1[] = + { "We're at the beginning already.", + "My memories are hazy before this.", + "Stop, you're making me dizzy.", + "Can't take tail of empty list." }; + static unsigned int undo_index = 0; + const char *words2[] = + { "Be more careful next time.", + "I won't judge you; I'm a computer.", + "Sure, as if time travel is easy.", + "You're pushing your luck, kiddo.", + "Next you'll ask for lessons?", + }; + static unsigned int undo_index2 = 0; + if (e->board->moves == 0) { + print_string(gameover ? + "Just accept it and move on." : + words1[undo_index++ % ARRAY_SIZE(words1)]); + } else { + engine_undomove(e); + if (player_mode == bot_white) + player_mode = bot_black; + else if (player_mode == bot_black) + player_mode = bot_white; + flipped = !flipped; + gameover = checkgameover(); // refresh status string + assert(!gameover && "Game over after undo??"); + if (!need_redraw) draw_player_str(); + if (!need_redraw) draw_board(e->board); + if (!need_redraw) draw_status_str(); + print_string(words2[undo_index2++ % + ARRAY_SIZE(words2)]); + } + /* Moving */ + } else if (0 == strcmp(inbuf, "go")) { + if (gameover) { + print_string(nogame); + } else { + player_mode = e->board->tomove == WHITE ? + bot_white : bot_black; + flipped = !flipped; + if (!need_redraw) draw_player_str(); + if (!need_redraw) draw_board(e->board); + makemove(); + if (!need_redraw) draw_board(e->board); + gameover = checkgameover(); + if (!need_redraw) draw_status_str(); + } + } else if (!!move_fromstring(inbuf)) { + char *errmsg = NULL; + if (gameover) { + print_string(nogame); + } else if (engine_applymove(e, inbuf, &errmsg)) { + if ((gameover = checkgameover())) { + print_string("Good game!"); + } else if (player_mode != human) { + /* Make a move in response. */ + if (!need_redraw) draw_status_str(); + if (!need_redraw) draw_board(e->board); + makemove(); + if (!need_redraw) draw_board(e->board); + if ((gameover = checkgameover())) { + print_string("Good game!"); + } + } else { + flipped = !flipped; + if (!need_redraw) draw_board(e->board); + } + if (!need_redraw) draw_status_str(); + } else { + assert(errmsg != NULL); + print_string(errmsg); + } + /* Fail */ + } else { + print_string(strlen(inbuf) ? "I didn't understand that." : + "You'll have to be more specific."); + } + /* Update display to reflect changes */ + if (need_redraw) { + redraw(e->board); + } else { + draw_console(); + draw_prompt(); + } + } + panic("completed infinite loop!"); + return 31337; +} diff --git a/410user/progs/cat.c b/410user/progs/cat.c new file mode 100644 index 0000000..9d2ef97 --- /dev/null +++ b/410user/progs/cat.c @@ -0,0 +1,30 @@ +// Simple program to print out files. +// Michael J. Sullivan, Spring 2013 + +#include <syscall.h> +#include <stdlib.h> +#include <stdio.h> + +#define BUFSIZE 87 // "four score and seven" + +int main(int argc, char **argv) +{ + char buf[BUFSIZE]; + int i; + for (i = 1; i < argc; i++) { + char *file = argv[i]; + int offset = 0; + int amt_read; + while ((amt_read = readfile(file, buf, BUFSIZE, offset)) > 0) { + print(amt_read, buf); + offset += amt_read; + } + if (amt_read < 0) { + printf("error reading from file %s at offset %d\n", + file, offset); + return -1; + } + } + + return 0; +} diff --git a/410user/progs/cho.c b/410user/progs/cho.c new file mode 100644 index 0000000..2270a75 --- /dev/null +++ b/410user/progs/cho.c @@ -0,0 +1,103 @@ +/** @file 410user/progs/cho.c + * @author de0u + * @brief "Continuous hours of operation" - runs many tests. + * @public yes + * @for p3 + * @covers fork exec wait set_status vanish sleep + * @status done + */ + +#include <syscall.h> +#include <stdlib.h> +#include <stdio.h> +#include "410_tests.h" +#include <report.h> + +DEF_TEST_NAME("cho:"); + +/* Every UPDATE_FREQUENCY reaps, print out an update of + * how many children of each type are left. + */ +#define UPDATE_FREQUENCY 50 + +#define SERIOUSLY_DEAD (0xdeaddead) + +struct prog { + char *name; + int pid; + int count; +} progs[] = { + {"sleep_test1", -1, 13}, + {"wait_getpid", -1, 100}, + {"wild_test1", -1, 100}, + {"exec_basic", -1, 100}, + {"print_basic", -1, 100} +}; + +int main() +{ + int active_progs = sizeof (progs) / sizeof (progs[0]); + int active_processes = 0; + struct prog *p, *fence; + int reap_count = 0; + + report_start(START_CMPLT); + TEST_PROG_ENGAGE(300); + + fence = progs + active_progs; + + while ((active_progs > 0) || (active_processes > 0)) { + + /* launch some processes */ + for (p = progs; p < fence; ++p) { + if ((p->count > 0) && (p->pid == -1)) { + int pid = fork(); + + if (pid < 0) { + sleep(1); + } else if (pid == 0) { + char *args[2]; + + report_misc("After fork(): I am a child!"); + TEST_PROG_PROGRESS; + + args[0] = p->name; + args[1] = 0; + exec(p->name, args); + report_misc("exec() failed (missing object?)"); + report_end(END_FAIL); + exit(SERIOUSLY_DEAD); + } else { + p->pid = pid; + ++active_processes; + } + } + } + + /* reap a child */ + if (active_processes > 0) { + int pid, status; + pid = wait(&status); + if (status == SERIOUSLY_DEAD) + exit(SERIOUSLY_DEAD); + report_fmt("wait() done: %d with status %d", pid, status); + TEST_PROG_PROGRESS; + ++reap_count; + for (p = progs; p < fence; ++p) { + if (p->pid == pid) { + p->pid = -1; + --p->count; + if (p->count <= 0) + --active_progs; + --active_processes; + } + if (reap_count % UPDATE_FREQUENCY == 0) { + report_fmt("%s: %d left", p->name, p->count); + } + } + } + } + + report_end(END_SUCCESS); + exit(0); +} diff --git a/410user/progs/cho2.c b/410user/progs/cho2.c new file mode 100644 index 0000000..178ebad --- /dev/null +++ b/410user/progs/cho2.c @@ -0,0 +1,108 @@ +/** @file 410user/progs/cho2.c + * @author de0u + * @author ctokar + * @brief "Continuous hours of operation" - run many tests. + * @public yes + * @for p3 + * @covers fork exec wait gettid set_status vanish sleep + * @todo Progress checking? + */ + +#include <syscall.h> +#include <stdlib.h> +#include <stdio.h> +#include <simics.h> +#include "410_tests.h" +#include <report.h> + +DEF_TEST_NAME("cho2:"); + +/* Every UPDATE_FREQUENCY reaps, print out an update of + * how many children of each type are left. + */ +#define UPDATE_FREQUENCY 50 + +#define SERIOUSLY_DEAD (0xdeaddead) + +struct prog { + char *name; + int pid; + int count; +} progs[] = { + {"getpid_test1", -1, 13}, + {"yield_desc_mkrun", -1, 100}, + {"remove_pages_test1", -1, 100}, + {"loader_test1", -1, 100}, + {"fork_wait", -1, 100}, + {"swexn_rampage", -1, 1}, + {"mem_permissions", -1, 31}, + {"minclone_mem", -1, 17} +}; + +int main() +{ + int active_progs = sizeof (progs) / sizeof (progs[0]); + int active_processes = 0; + struct prog *p, *fence; + int reap_count = 0; + + report_start(START_CMPLT); + TEST_PROG_ENGAGE(300); + + fence = progs + active_progs; + + while ((active_progs > 0) || (active_processes > 0)) { + + /* launch some processes */ + for (p = progs; p < fence; ++p) { + if ((p->count > 0) && (p->pid == -1)) { + int pid = fork(); + + if (pid < 0) { + sleep(1); + } else if (pid == 0) { + char *args[2]; + + report_misc("After fork(): I am a child!"); + TEST_PROG_PROGRESS; + + args[0] = p->name; + args[1] = 0; + exec(p->name, args); + report_misc("exec() failed (missing object?)"); + report_end(END_FAIL); + exit(SERIOUSLY_DEAD); + } else { + p->pid = pid; + ++active_processes; + } + } + } + + /* reap a child */ + if (active_processes > 0) { + int pid, status; + pid = wait(&status); + if (status == SERIOUSLY_DEAD) + exit(SERIOUSLY_DEAD); + report_fmt("wait() done: %d with status %d", pid, status); + TEST_PROG_PROGRESS; + ++reap_count; + for (p = progs; p < fence; ++p) { + if (p->pid == pid) { + p->pid = -1; + --p->count; + if (p->count <= 0) + --active_progs; + --active_processes; + } + if (reap_count % UPDATE_FREQUENCY == 0) { + report_fmt("%s: %d left", p->name, p->count); + } + } + } + } + + report_end(END_SUCCESS); + exit(0); +} diff --git a/410user/progs/cho_variant.c b/410user/progs/cho_variant.c new file mode 100644 index 0000000..4485f00 --- /dev/null +++ b/410user/progs/cho_variant.c @@ -0,0 +1,171 @@ +/** @file 410user/progs/cho_variant.c + * @author de0u + * @author ctokar + * @author nwf + * @brief "Continuous hours of operation" - runs many tests. + * @public yes + * @for p3 + * @covers fork exec wait set_status vanish sleep remove_pages new_pages + * @covers deschedule make_runnable yield + * @status done + */ + +#include <syscall.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "410_tests.h" +#include <report.h> + +DEF_TEST_NAME("cho_variant:"); + +/** @brief Every UPDATE_FREQUENCY reaps, print out an update of + * how many children of each type are left. + */ +static const int UPDATE_FREQUENCY = 10; + +/** @brief Error signaling return code. + * @pre Ensure that no test program in the table below returns this + * constant. + */ +static const int DEAD_TEST_PROGRAM_RETURN = 0xDEADDEAD; + +/** @brief Program table */ +struct prog { + char *name; + int expected; + int pid; + int count; +} progs[] + = { + {"exec_basic", 1, -1, 5}, + {"fork_wait", 0, -1, 5}, + {"loader_test1", 0, -1, 5}, + {"loader_test2", 42, -1, 5}, + {"make_crash",10000,-1, 1}, + {"print_basic",0,-1,5}, + {"remove_pages_test1", 0, -1, 2}, + {"remove_pages_test2", -2, -1, 5}, /* Should die: wild pointer */ + {"sleep_test1", 42, -1, 5}, /* indistinguishible outcomes */ + {"stack_test1", 42, -1, 5}, + {"wild_test1", -2, -1, 5}, /* Should die: wild pointer */ + {"yield_desc_mkrun", 0, -1, 5}, +}; + +int main(int argc, char **argv) +{ + int active_progs = sizeof (progs) / sizeof (progs[0]); + int active_processes = 0; + struct prog *p, *fence; + int reap_count = 0; + int matched; + int magic_break = 0; + + if ( argc > 1 ) + { + if ( !strcmp("MAGIC", argv[1]) ) + { + magic_break = 1; + } + } + + report_start(START_CMPLT); + TEST_PROG_ENGAGE(1200); + + fence = progs + active_progs; + + while ((active_progs > 0) || (active_processes > 0)) { + + /* launch some processes */ + for (p = progs; p < fence; ++p) { + if ((p->count > 0) && (p->pid == -1)) { + int pid = fork(); + + if (pid < 0) { + sleep(1); + } else if (pid == 0) { + char *args[2]; + + report_fmt("after fork(): I am a child (prog %s, tid %d)", + p->name, gettid()); + TEST_PROG_PROGRESS; + + args[0] = p->name; + args[1] = 0; + exec(p->name, args); + report_misc("exec() failed"); + /* Leave it to the parent to emit the test failure message */ + if ( magic_break ) + { + MAGIC_BREAK; + } + exit(DEAD_TEST_PROGRAM_RETURN); + } else { + p->pid = pid; + ++active_processes; + } + } + } + + /* reap a child */ + if (active_processes > 0) { + int pid, status; + pid = wait(&status); + if (status == DEAD_TEST_PROGRAM_RETURN) + { + lprintf("%s%s%s", TEST_PFX,test_name,TEST_END_FAIL); + if ( magic_break ) + { + MAGIC_BREAK; + } + exit(-1); + } + TEST_PROG_PROGRESS; + ++reap_count; + for (p = progs, matched = 0; p < fence; ++p) { + if (p->pid == pid) { + matched = 1; + lprintf("%s%s After wait(): pid = %d, prog = %s", + TEST_PFX, test_name, pid, p->name); + if ( status != p->expected ) + { + lprintf("=( TEST FAILED: %s; EXPECT %d GOT %d", + p->name, p->expected, status ); + lprintf("%s%s%s", TEST_PFX,test_name,TEST_END_FAIL); + if ( magic_break ) + { + MAGIC_BREAK; + } + exit(-1); + } + p->pid = -1; + --p->count; + if (p->count <= 0) + --active_progs; + --active_processes; + } + if (reap_count % UPDATE_FREQUENCY == 0) + { + /* Display progress on softcons as well, in condensed form */ + report_fmt("%s: %d left", p->name, p->count); + printf("[%s,%d]",p->name, p->count); + } + } + if ( matched == 0 ) + { + report_fmt("unexpected waited pid %d (status %d)", pid, status); + report_end(END_FAIL); + if ( magic_break ) + { + MAGIC_BREAK; + } + exit(-1); + } + } + if (reap_count % UPDATE_FREQUENCY == 0) + print(1, "\n"); + } + + report_end(END_SUCCESS); + exit(0); +} diff --git a/410user/progs/chow.c b/410user/progs/chow.c new file mode 100644 index 0000000..e0c4e02 --- /dev/null +++ b/410user/progs/chow.c @@ -0,0 +1,142 @@ +/** @file 410user/progs/chow.c + * @author acrichto + * @brief "Continuous hours of operation (work)" - + * runs a bunch of user-space code, not just syscalls + * @public yes + * @for p4-smp + * @status done + */ + +#include <syscall.h> +#include <stdlib.h> +#include <stdio.h> +#include "410_tests.h" +#include <report.h> + +DEF_TEST_NAME("chow:"); + +/* Every UPDATE_FREQUENCY reaps, print out an update of + * how many children of each type are left. + */ +#define UPDATE_FREQUENCY 50 + +#define SERIOUSLY_DEAD (0xdeaddead) + +struct prog { + char *name; + int pid; + int count; +} progs[] = { + {"fib", -1, 20}, + {"ack", -1, 20}, + {"yield_desc_mkrun", -1, 100}, + {"fork_wait", -1, 100} +}; + +char numbers[10][5][10] = { + {" ___ ", " / _ \\ ", "| | | |", "| |_| |", " \\___/ "}, + {" _ ", "/ |", "| |", "| |", "|_|"}, + {" ____ ", "|___ \\ ", " __) |", " / __/ ", "|_____|"}, + {" _____ ", "|___ / ", " |_ \\ ", " ___) |", "|____/ "}, + {" _ _ ", "| || | ", "| || |_ ", "|__ _|", " |_| "}, + {" ____ ", "| ___| ", "|___ \\ ", " ___) |", "|____/ "}, + {" __ ", " / /_ ", "| '_ \\ ", "| (_) |", " \\___/ "}, + {" _____ ", "|___ |", " / / ", " / / ", " /_/ "}, + {" ___ ", " ( _ ) ", " / _ \\ ", "| (_) |", " \\___/ "}, + {" ___ ", " / _ \\ ", "| (_) |", " \\__, |", " /_/ "}, +}; + +int main() +{ + int active_progs = sizeof (progs) / sizeof (progs[0]); + int active_processes = 0; + struct prog *p, *fence; + int reap_count = 0; + + report_start(START_CMPLT); + TEST_PROG_ENGAGE(1200); + + fence = progs + active_progs; + int ticks = get_ticks(); + + while ((active_progs > 0) || (active_processes > 0)) { + + /* launch some processes */ + for (p = progs; p < fence; ++p) { + if ((p->count > 0) && (p->pid == -1)) { + int pid = fork(); + + if (pid < 0) { + sleep(1); + } else if (pid == 0) { + char *args[2]; + + report_misc("After fork(): I am a child!"); + TEST_PROG_PROGRESS; + + args[0] = p->name; + args[1] = 0; + exec(p->name, args); + report_misc("exec() failed (missing object?)"); + report_end(END_FAIL); + exit(SERIOUSLY_DEAD); + } else { + p->pid = pid; + ++active_processes; + } + } + } + + /* reap a child */ + if (active_processes > 0) { + int pid, status; + pid = wait(&status); + if (status == SERIOUSLY_DEAD) + exit(SERIOUSLY_DEAD); + report_fmt("wait() done: %d with status %d", pid, status); + TEST_PROG_PROGRESS; + ++reap_count; + for (p = progs; p < fence; ++p) { + if (p->pid == pid) { + p->pid = -1; + --p->count; + if (p->count <= 0) + --active_progs; + --active_processes; + } + if (reap_count % UPDATE_FREQUENCY == 0) { + report_fmt("%s: %d left", p->name, p->count); + } + } + } + } + + ticks = get_ticks() - ticks; + + int pow = 10; + while (pow * 10 < ticks) pow *= 10; + + printf("\n" + "*****************************************************************\n" + "\n" + " Total ticks taken\n" + "\n"); + + int i; + for (i = 0; i < 5; i++) { + printf(" "); + int tmp = ticks; + int tmppow = pow; + + while (tmppow > 0) { + printf("%s ", numbers[(tmp / tmppow) % 10][i]); + tmppow /= 10; + } + printf("\n"); + } + printf("\n" + "*****************************************************************\n"); + + report_end(END_SUCCESS); + exit(0); +} diff --git a/410user/progs/ck1.c b/410user/progs/ck1.c new file mode 100644 index 0000000..c5aca41 --- /dev/null +++ b/410user/progs/ck1.c @@ -0,0 +1,26 @@ +/** @file 410user/progs/ck1.c + * @author ? + * @author elly1 + * @brief Runs the checkpoint 1 script. + * @public yes + * @for p3 + * @covers gettid + * @status done + */ + +#include <syscall.h> /* gettid() */ +#include <simics.h> /* lprintf() */ + +/* Main */ +int main() +{ + int tid; + + sim_ck1(); + tid = gettid(); + + lprintf("my tid is: %d", tid); + + while (1) + continue; +} diff --git a/410user/progs/coolness.c b/410user/progs/coolness.c new file mode 100644 index 0000000..b37d4a6 --- /dev/null +++ b/410user/progs/coolness.c @@ -0,0 +1,26 @@ +/** @file 410user/progs/coolness.c + * @author de0u + * @brief Tests fork, exec, and context-switching. + * @public yes + * @for p3 + * @covers fork gettid exec + * @status done + */ + +#include <syscall.h> +#include <simics.h> + +char *program = "peon"; +char *args[2]; + +int main() { + + fork(); + args[0] = program; + fork(); + + exec(program, args); + + while(1) + lprintf("ULTIMATE BADNESS"); +} diff --git a/410user/progs/deschedule_hang.c b/410user/progs/deschedule_hang.c new file mode 100644 index 0000000..7f63a5e --- /dev/null +++ b/410user/progs/deschedule_hang.c @@ -0,0 +1,32 @@ +/** @file 410user/progs/deschedule_hang.c + * @author mpa + * @brief Tests that deschedule() doesn't return without a corresponding + * make_runnable() call. + * @public yes + * @for p3 + * @covers deschedule + * @status done + */ + +#include <syscall.h> +#include <stdlib.h> +#include <stdio.h> +#include "410_tests.h" +#include <report.h> + +DEF_TEST_NAME("deschedule_hang:"); + +int main() +{ + int error, reject; + report_start(START_4EVER); + + reject = 0; + /* stop running for quite a while */ + error = deschedule(&reject); + + report_fmt("deschedule() returned %d", error); + + report_end(END_FAIL); + exit(1); +} diff --git a/410user/progs/exec_basic.c b/410user/progs/exec_basic.c new file mode 100644 index 0000000..5cd2f6d --- /dev/null +++ b/410user/progs/exec_basic.c @@ -0,0 +1,33 @@ +/** @file 410user/progs/exec_basic.c + * @author mpa + * @brief Tests basic functionality of exec() + * @public yes + * @for p3 + * @covers exec + * @status done + */ + +#include <syscall.h> +#include <stdlib.h> +#include <stdio.h> +#include <simics.h> +#include "410_tests.h" + +DEF_TEST_NAME("exec_basic:"); + +int main() +{ + + REPORT_LOCAL_INIT; + + char *name = "exec_basic_helper"; + char *args[] = {name, 0}; + + REPORT_START_CMPLT; + + REPORT_ON_ERR(exec(name,args)); + + REPORT_END_FAIL; + + exit(-1); +} diff --git a/410user/progs/exec_basic_helper.c b/410user/progs/exec_basic_helper.c new file mode 100644 index 0000000..c36b6be --- /dev/null +++ b/410user/progs/exec_basic_helper.c @@ -0,0 +1,25 @@ +/** @file 410user/progs/exec_basic_helper.c + * @author mpa + * @brief Run by exec_basic to test exec. + * @public yes + * @for p3 + * @covers nothing + * @status done + * @note Helper. + */ + +#include <syscall.h> +#include <stdlib.h> +#include <stdio.h> +#include <simics.h> +#include "410_tests.h" + +DEF_TEST_NAME("exec_basic:"); + +int main() +{ + REPORT_MISC("exec_basic_helper main() starting..."); + REPORT_END_SUCCESS; + + exit(1); +} diff --git a/410user/progs/exec_nonexist.c b/410user/progs/exec_nonexist.c new file mode 100644 index 0000000..f2cb8dd --- /dev/null +++ b/410user/progs/exec_nonexist.c @@ -0,0 +1,31 @@ +/** @file 410user/progs/exec_nonexist.c + * @author mpa + * @brief Tests exec()ing a nonexistent file. + * @public yes + * @for p3 + * @covers exec + * @status done + */ + +#include <syscall.h> +#include <stdlib.h> +#include <stdio.h> +#include "410_tests.h" +#include <report.h> + +DEF_TEST_NAME("exec_nonexist:"); + +int main() { + char *name = "exec_a_random_file_that_does_not_exist"; + char *args[] = {name, 0}; + report_start(START_CMPLT); + + if (exec(name,args) >= 0) { + report_misc("exec() did not return an error code"); + report_end(END_FAIL); + exit(-1); + } + + report_end(END_SUCCESS); + exit(0); +} diff --git a/410user/progs/fib.c b/410user/progs/fib.c new file mode 100644 index 0000000..4dc3ae9 --- /dev/null +++ b/410user/progs/fib.c @@ -0,0 +1,49 @@ +/** @file 410user/progs/fib.c + * @author acrichto + * @brief Computes Fibonacci series in multiple threads + * @public yes + * @for p4-smp + * @status done + */ + +#include <410_tests.h> +#include <stdio.h> +#include <syscall.h> +#include <thread.h> +#include <thrgrp.h> + +DEF_TEST_NAME("fib:"); + +#define THREADS 8 +#define FIBN 32 + +typedef void*(thr_func)(void*); + +int fib(int n) { + if (n < 2) return n; + return fib(n - 1) + fib(n - 2); +} + +int main() { + thr_init(4096); + int ticks = get_ticks(); + int i, answer, guess; + thrgrp_group_t group; + + REPORT_ON_ERR(thrgrp_init_group(&group)); + for (i = 0; i < THREADS; i++) { + REPORT_ON_ERR(thrgrp_create(&group, (thr_func*) fib, (void*) FIBN)); + } + + REPORT_ON_ERR(thrgrp_join(&group, (void*) &answer)); + for (i = 1; i < THREADS; i++) { + REPORT_ON_ERR(thrgrp_join(&group, (void*) &guess)); + if (guess != answer) { + REPORT_END_FAIL; + } + } + printf("fib(%d) = %d\n", FIBN, answer); + printf("ticks taken: %d\n", get_ticks() - ticks); + + thr_exit(0); +} diff --git a/410user/progs/fork_bomb.c b/410user/progs/fork_bomb.c new file mode 100644 index 0000000..a64754f --- /dev/null +++ b/410user/progs/fork_bomb.c @@ -0,0 +1,27 @@ +/** @file 410user/progs/fork_bomb.c + * @author zra + * @brief Tests fork() in low-memory conditions. + * @public yes + * @for p3 + * @covers fork oom + * @status done + */ + +/* Includes */ +#include <syscall.h> /* for fork */ +#include <stdlib.h> +#include "410_tests.h" +#include <report.h> + +DEF_TEST_NAME("fork_bomb:"); + +/* Main */ +int main() { + report_start(START_4EVER); + TEST_PROG_ENGAGE(200); + + while (1) { + fork(); + TEST_PROG_PROGRESS; + } +} diff --git a/410user/progs/fork_exit_bomb.c b/410user/progs/fork_exit_bomb.c new file mode 100644 index 0000000..a0a8fbc --- /dev/null +++ b/410user/progs/fork_exit_bomb.c @@ -0,0 +1,41 @@ +/** @file 410user/progs/fork_exit_bomb.c + * @author ? + * @brief Tests many invocations of fork/exit + * @public yes + * @for p3 + * @covers fork set_status vanish + * @status done + */ + +#include <syscall.h> +#include <stdlib.h> +#include <stdio.h> +#include "410_tests.h" +#include <report.h> + +DEF_TEST_NAME("fork_exit_bomb:"); + +int main(int argc, char *argv[]) { + int pid = 0; + int count = 0; + + report_start(START_CMPLT); + TEST_PROG_ENGAGE(200); + + lprintf("parent pid: %d", gettid()); + + while(count < 1000) { + if((pid = fork()) == 0) { + exit(42); + } + if(pid < 0) { + break; + } + count++; + report_fmt("child: %d", pid); + TEST_PROG_PROGRESS; + } + + report_end(END_SUCCESS); + exit(42); +} diff --git a/410user/progs/fork_test1.c b/410user/progs/fork_test1.c new file mode 100644 index 0000000..45fa9d6 --- /dev/null +++ b/410user/progs/fork_test1.c @@ -0,0 +1,41 @@ +/** @file 410user/progs/fork_test1.c + * @author zra + * @brief Tests basic functionality of fork() + * @public yes + * @for p3 + * @covers fork + * @status done + */ + +/* Includes */ +#include <syscall.h> /* for fork, getpid */ +#include <stdlib.h> /* for exit */ +#include <stdio.h> /* for lprintf */ +#include "410_tests.h" +#include <report.h> + +DEF_TEST_NAME("fork_test1:"); + +/* Main */ +int main(int argc, char *argv[]) +{ + int pid; + + report_start(START_CMPLT); + pid = fork(); + + if( pid < 0 ) { + report_end(END_FAIL); + exit(-1); + } + + if( pid > 0 ) { + report_fmt("parent: tid = %d", gettid()); + } + else { + report_fmt("child: tid = %d", gettid()); + } + + report_end(END_SUCCESS); + exit( 1 ); +} diff --git a/410user/progs/fork_wait.c b/410user/progs/fork_wait.c new file mode 100644 index 0000000..791e3e4 --- /dev/null +++ b/410user/progs/fork_wait.c @@ -0,0 +1,46 @@ +/** @file 410user/progs/fork_wait.c + * @author zra + * @brief Tests fork() and wait(). + * @public yes + * @for p3 + * @covers fork wait set_status vanish + * @status done + */ + +#include <syscall.h> +#include <stdlib.h> +#include "410_tests.h" +#include <report.h> + +DEF_TEST_NAME("fork_wait:"); + +int main() +{ + int pid, status; + + report_start(START_CMPLT); + pid = fork(); + + if (pid < 0) { + report_end(END_FAIL); + exit(-1); + } + + if (pid == 0) { + exit(17); + report_end(END_FAIL); /* panic("vanish() didn't"); */ + } + + if (wait(&status) != pid) { + report_end(END_FAIL); + exit(-1); + } + + if (status != 17) { + report_end(END_FAIL); + exit(-1); + } + + report_end(END_SUCCESS); + exit(0); +} diff --git a/410user/progs/fork_wait_bomb.c b/410user/progs/fork_wait_bomb.c new file mode 100644 index 0000000..bb5581b --- /dev/null +++ b/410user/progs/fork_wait_bomb.c @@ -0,0 +1,50 @@ +/** @file 410user/progs/fork_wait_bomb.c + * @author ? + * @brief Tests fork, wait, and exit in stress conditions. + * @public yes + * @for p3 + * @covers fork wait set_status vanish + * @status done + */ + +#include <syscall.h> +#include <stdlib.h> +#include "410_tests.h" +#include <report.h> + +DEF_TEST_NAME("fork_wait_bomb:"); + +int main(int argc, char *argv[]) { + int pid = 0; + int count = 0; + int ret_val; + int wpid; + + report_start(START_CMPLT); + TEST_PROG_ENGAGE(200); + report_fmt("parent: %d", gettid()); + + while(count < 1000) { + if((pid = fork()) == 0) { + exit(42); + } + if(pid < 0) { + break; + } + + count++; + + report_fmt("child: %d", pid); + TEST_PROG_PROGRESS; + + wpid = wait(&ret_val); + + if(wpid != pid || ret_val != 42) { + report_end(END_FAIL); + exit(42); + } + } + + report_end(END_SUCCESS); + exit(42); +} diff --git a/410user/progs/getpid_test1.c b/410user/progs/getpid_test1.c new file mode 100644 index 0000000..5f45a3d --- /dev/null +++ b/410user/progs/getpid_test1.c @@ -0,0 +1,34 @@ +/** @file 410user/progs/getpid_test1.c + * @author zra + * @brief Tests gettid(). + * @public yes + * @for p2 p3 + * @covers gettid + * @status done + */ + +/* Includes */ +#include "410_tests.h" +#include <report.h> +#include <simics.h> /* for lprintf */ +#include <stdlib.h> /* for exit */ +#include <syscall.h> /* for getpid */ + +DEF_TEST_NAME("getpid_test1:"); + +/* Main */ +int main() { + int pid; + + report_start(START_CMPLT); + pid = gettid(); + lprintf("%s my pid is: %d", test_name, pid); + + if (pid == gettid()) { + report_end(END_SUCCESS); + exit(0); + } else { + report_end(END_FAIL); + exit(-1); + } +} diff --git a/410user/progs/halt_test.c b/410user/progs/halt_test.c new file mode 100644 index 0000000..65a5b3a --- /dev/null +++ b/410user/progs/halt_test.c @@ -0,0 +1,26 @@ +/** @file 410user/progs/halt_test.c + * @author mpa + * @brief Tests the basic functionality of halt() + * @public yes + * @for p2 p3 + * @covers halt + * @status done + */ + +#include <syscall.h> +#include <stdlib.h> +#include <stdio.h> +#include <simics.h> +#include "410_tests.h" + +DEF_TEST_NAME("halt_test:"); + +int main() +{ + REPORT_START_ABORT; + + halt(); + + REPORT_END_FAIL; + exit(-1); +} diff --git a/410user/progs/idle.c b/410user/progs/idle.c new file mode 100644 index 0000000..e50c6d1 --- /dev/null +++ b/410user/progs/idle.c @@ -0,0 +1,14 @@ +/** @file 410user/progs/idle.c + * @author ? + * @brief Idle program. + * @public yes + * @for p2 p3 + * @covers + * @status done + */ + +int main() +{ + while (1) { + } +} diff --git a/410user/progs/init.c b/410user/progs/init.c new file mode 100644 index 0000000..f61e1a7 --- /dev/null +++ b/410user/progs/init.c @@ -0,0 +1,28 @@ +/** @file 410user/progs/init.c + * @author ? + * @brief Initial program. + * @public yes + * @for p2 p3 + * @covers fork exec wait print + * @status done + */ + +#include <syscall.h> +#include <stdio.h> + +int main() +{ + int pid, exitstatus; + char shell[] = "shell"; + char * args[] = {shell, 0}; + + while(1) { + pid = fork(); + if (!pid) + exec(shell, args); + + while (pid != wait(&exitstatus)); + + printf("Shell exited with status %d; starting it back up...", exitstatus); + } +} diff --git a/410user/progs/knife.c b/410user/progs/knife.c new file mode 100644 index 0000000..f982f09 --- /dev/null +++ b/410user/progs/knife.c @@ -0,0 +1,43 @@ +/** @file 410user/progs/knife.c + * @author mpa + * @brief Tests fork and context-switching. + * @public yes + * @for p3 + * @covers fork gettid + * @status done + */ + +#include <syscall.h> +#include <stdio.h> +#include <simics.h> + +#define DELAY (16*1024) + +int gcc_please_do_not_optimize_too_much = 0; + +void foo() { + ++gcc_please_do_not_optimize_too_much; +} + +/* this function eats up a bunch of cpu cycles */ +void slow() { + int i; + + for (i = 0; i < DELAY; i++) foo(); +} + +int main() { + + int tid; + + if ((tid = fork()) == 0) + while(1) { + slow(); + lprintf("child: %d", gettid()); + } + else + while(1) { + slow(); + lprintf("parent: %d\t\tchild:%d", gettid(), tid); + } +} diff --git a/410user/progs/loader_test1.c b/410user/progs/loader_test1.c new file mode 100644 index 0000000..68d389e --- /dev/null +++ b/410user/progs/loader_test1.c @@ -0,0 +1,94 @@ +/** @file 410user/progs/loader_test1.c + * @author ? + * @author nwf + * @brief Tests loading of .data and .bss + * @public yes + * @for p3 + * @covers exec + * @status done + */ + +#include <stdlib.h> +#include <syscall.h> +#include "410_tests.h" +#include <report.h> + +DEF_TEST_NAME("loader_test1:"); + +int feed = 0xfeed; +int face = 0xface; +char x[8192] = { 1, 2, 3 }; +int face2 = 0xface; +void *self = (void *)&self; +const void *cself = (void *)&cself; +int fred; + +int main(int argc, char** argv) { + + int *ip; + int ret=0; + + report_start(START_CMPLT); + + if (feed != 0xfeed) { + /* fatal */ + report_misc(".data contains the wrong value"); + report_end(END_FAIL); + ret--; + } + + if (face != 0xface) { + /* fatal */ + report_misc(".data contains the wrong value"); + report_end(END_FAIL); + ret--; + } + + ip = &feed; + ++ip; + +#ifdef notdef +// This was not promised by the language but was essentially +// always true... "fixed" by gcc 4.6.1-9 [gbrunsta] + if (*ip != 0xface) { + /* fatal */ + report_misc(".data out of order... how did the previous two tests work?"); + report_end(END_FAIL); + ret--; + } +#endif + + if (fred) { + /* fatal */ + report_misc(".bss not zeroed"); + report_end(END_FAIL); + ret--; + } + + if (face2 != 0xface) { + /* fatal */ + report_misc(".data contains wrong value"); + report_end(END_FAIL); + ret--; + } + + if (&feed >= &fred) { + /* fatal -- if even observable */ + report_misc("linker botch???"); + report_end(END_FAIL); + ret--; + } + + if ((self != (void *)&self) || (cself != (void *)&cself)) { + report_misc("One of the flay-rods has gone out askew on the treadle!"); + report_end(END_FAIL); + ret--; + } + + if(ret==0) + { + report_end(END_SUCCESS); + return 0; + } + exit(42); +} diff --git a/410user/progs/loader_test2.c b/410user/progs/loader_test2.c new file mode 100644 index 0000000..8183ae0 --- /dev/null +++ b/410user/progs/loader_test2.c @@ -0,0 +1,273 @@ +/** @file 410user/progs/loader_test2.c + * @author ? + * @brief Tests loading large code sections. + * @public yes + * @for p3 + * @covers exec + * @status done + */ + +#include <stdlib.h> +#include <syscall.h> +#include "410_tests.h" +#include <report.h> + +DEF_TEST_NAME("loader_test2:"); + +void foo(void); +void bar(void); +void no44(void); + +extern int zipper; + +int main(int argc, char** argv) { + report_start(START_CMPLT); + + foo(); + bar(); + + if (zipper != 45) { + report_misc("FAILED: code overwriting data?"); + no44(); + report_end(END_FAIL); + exit(-1); + } else { + report_end(END_SUCCESS); + exit(42); + } + +} + +void foo(void) { + /* print something encouraging */ + report_misc("first called worked"); +} + +void no0(void) { + /* fatal */ + report_end(END_FAIL); +} + +void no1(void) { + /* fatal */ + no0(); +} + +void no2(void) { + /* fatal */ + no1(); +} + +void no3(void) { + /* fatal */ + no2(); +} + +void no4(void) { + /* fatal */ + no3(); +} + +void no5(void) { + /* fatal */ + no4(); +} + +void no6(void) { + /* fatal */ + no5(); +} + +void no7(void) { + /* fatal */ + no6(); +} + +void no8(void) { + /* fatal */ + no7(); +} + +void no9(void) { + /* fatal */ + no8(); +} + +void no10(void) { + /* fatal */ + no9(); +} + +void no11(void) { + /* fatal */ + no10(); +} + +void no12(void) { + /* fatal */ + no11(); +} + +void no13(void) { + /* fatal */ + no12(); +} + +void no14(void) { + /* fatal */ + no13(); +} + +void no15(void) { + /* fatal */ + no14(); +} + +void no16(void) { + /* fatal */ + no15(); +} + +void no17(void) { + /* fatal */ + no16(); +} + +void no18(void) { + /* fatal */ + no17(); +} + +void no19(void) { + /* fatal */ + no18(); +} + +void no20(void) { + /* fatal */ + no19(); +} +void no21(void) { + /* fatal */ + no20(); +} + +void no22(void) { + /* fatal */ + no21(); +} + +void no23(void) { + /* fatal */ + no22(); +} + +void no24(void) { + /* fatal */ + no23(); +} + +void no25(void) { + /* fatal */ + no24(); +} + +void no26(void) { + /* fatal */ + no25(); +} + +void no27(void) { + /* fatal */ + no26(); +} + +void no28(void) { + /* fatal */ + no27(); +} +void no29(void) { + /* fatal */ + no28(); +} + +void no30(void) { + /* fatal */ + no29(); +} + +void no31(void) { + /* fatal */ + no30(); +} + +void no32(void) { + /* fatal */ + no31(); +} + +void no33(void) { + /* fatal */ + no32(); +} + +void no34(void) { + /* fatal */ + no33(); +} + +void no35(void) { + /* fatal */ + no34(); +} + +void no36(void) { + /* fatal */ + no35(); +} + +void no37(void) { + /* fatal */ + no36(); +} + +void no38(void) { + /* fatal */ + no37(); +} + +void no39(void) { + /* fatal */ + no38(); +} + +void no40(void) { + /* fatal */ + no39(); +} + +void no41(void) { + /* fatal */ + no40(); +} + +void no42(void) { + /* fatal */ + no41(); +} + +void no43(void) { + /* fatal */ + no42(); +} + +void no44(void) { + /* fatal */ + no43(); +} + +void bar(void) { + report_misc("second call worked"); +} + +int zipper=45; diff --git a/410user/progs/make_crash.c b/410user/progs/make_crash.c new file mode 100644 index 0000000..7cece01 --- /dev/null +++ b/410user/progs/make_crash.c @@ -0,0 +1,50 @@ +/** @file 410user/progs/make_crash.c + * @author rsa + * @author kcaffrey + * @brief Forkbombs, sleeps for a while, then exec()s a helper + * @public yes + * @for p3 + * @covers fork, exec, wait + * @status done + */ + +#include <syscall.h> +#include <stdio.h> +#include "410_tests.h" + +DEF_TEST_NAME ("make_crash:"); + +int main(int argc, char **argv) { + int i, tid, status; + int parentTID = gettid (); + char *name = "make_crash_helper"; + char s_parentTID[11]; + sprintf(s_parentTID, "%d", parentTID); + char *argvec[] = {name, "evil test", s_parentTID, 0}; + char buf[100]; + REPORT_START_CMPLT; + + REPORT_MISC("This test brought to you by Group 35 (Fall 03) - rsa & kcaffrey\n"); + REPORT_MISC("Starting forks"); + + for(i=0; i<7; i++) { + if ((tid=fork())==0) { + sprintf(buf, " Starting sleep I am %d", gettid()); + REPORT_MISC(buf); + sleep(100); + } + } + + sprintf(buf, " Done with my forks, I am %d", gettid()); + REPORT_MISC(buf); + + while ((tid=wait(&status))>=0) { + sprintf(buf, " Reaped child %d with status %d, I am %d", tid, status, gettid()); + REPORT_MISC(buf); + } + + sleep(200); + exec(name, argvec); + + return -40; +} diff --git a/410user/progs/make_crash_helper.c b/410user/progs/make_crash_helper.c new file mode 100644 index 0000000..a5aa63e --- /dev/null +++ b/410user/progs/make_crash_helper.c @@ -0,0 +1,41 @@ +/** @file 410user/progs/make_crash_helper.c + * @author rza + * @author kcaffrey + * @brief Helper for make_crash. Forks and checks its tid. + * @public yes + * @for p3 + * @covers gettid fork + * @status done + * @note Helper. + */ + +#include <syscall.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "410_tests.h" + +DEF_TEST_NAME("make_crash:"); + +int main(int argc, char **argv) { + if (argc < 3) { + return -50; + } + char buf[200]; + sprintf(buf, " My program is %s, my argument is %s and %s TID=%d", argv[0], argv[1], argv[2], gettid()); + REPORT_MISC(buf); + + if (fork()==0) + return 0; + + REPORT_MISC(" I am an exec-ed parent"); + + /* Should print when parent execs and exits */ + if (gettid() == atoi(argv[2])) { + REPORT_END_SUCCESS; + return 10000; + } + + return gettid(); +} diff --git a/410user/progs/mem_eat_test.c b/410user/progs/mem_eat_test.c new file mode 100644 index 0000000..7e29275 --- /dev/null +++ b/410user/progs/mem_eat_test.c @@ -0,0 +1,58 @@ +/** @file 410user/progs/mem_eat_test.c + * @author ? + * @brief Grows the stack until it dies. + * @public yes + * @for p3 + * @covers oom autostack + * @status done + */ + +#include <limits.h> +#include <syscall.h> +#include <stdlib.h> +#include <stdio.h> +#include "410_tests.h" +#include <report.h> + +DEF_TEST_NAME("mem_eat_test:"); + +#define MEGABYTE (1024*1024) +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif + +void touch_array(char *p); +void foo(int index); + +int main(int argc, char *argv[]) { + report_start(START_ABORT); + foo(1); + report_end(END_FAIL); + return 42; +} + +/* touch one byte per page to run faster. + * this code is a separate function so gcc doesn't optimize + * away the array writing. + */ +void touch_array(char *p) { + int i; + for(i = MEGABYTE - 1; i >= 0; i -= PAGE_SIZE) { + p[i] = 'a'; + } +} + +void foo(int index) +{ + char local_array[MEGABYTE]; + + if (index == INT_MAX) + // We will never get here. But the notion that we might get + // here defeats clang's clever infinite-recursion detector. + return; + + touch_array(local_array); + + report_fmt("used %d pages = %d MB", index * (MEGABYTE / PAGE_SIZE), index); + foo(index + 1); +} diff --git a/410user/progs/mem_permissions.c b/410user/progs/mem_permissions.c new file mode 100644 index 0000000..eb6cc46 --- /dev/null +++ b/410user/progs/mem_permissions.c @@ -0,0 +1,98 @@ +/** @file 410user/progs/mem_permissions.c + * @author mpa + * @brief Tests memory permissions. + * @public yes + * @for p3 + * @covers vm + * @status done + */ + +#include <stdio.h> +#include <stdlib.h> +#include <syscall.h> +#include "410_tests.h" + +DEF_TEST_NAME("mem_permissions:"); + +/* forks off a task to die writing to the address */ +void attempt_write(int *addr) +{ + int pid, pid2, status = 333; + REPORT_LOCAL_INIT; + + REPORT_FAILOUT_ON_ERR((pid = fork())); + + if (pid == 0) { + *addr = 42; + + REPORT_END_FAIL; + exit(42); + } + + REPORT_FAILOUT_ON_ERR((pid2 = wait(&status))); + + if (pid != pid2) { + report_fmt("Bad pid %d (should be %d)", pid2, pid); + REPORT_END_FAIL; + exit(42); + } + if (status >= 0) { + report_fmt("Bad status %d", status); + REPORT_END_FAIL; + exit(42); + } + report_fmt("Good: attempt_write(0x%x)", addr); +} + +/* forks off a task to die reading from the address */ +void attempt_read(int *addr) +{ + int pid, pid2, status = 444; + REPORT_LOCAL_INIT; + + REPORT_FAILOUT_ON_ERR((pid = fork())); + + if (pid == 0) { + pid = *addr; + + REPORT_END_FAIL; + exit(pid); + } + + REPORT_FAILOUT_ON_ERR((pid2 = wait(&status))); + + if (pid != pid2) { + report_fmt("Bad pid %d (should be %d)", pid2, pid); + REPORT_END_FAIL; + exit(42); + } + if (status >= 0) { + report_fmt("Bad status %d", status); + REPORT_END_FAIL; + exit(42); + } + report_fmt("Good: attempt_read(0x%x)", addr); +} + +const char header[4096] = "push rodata onto its own page"; +const char array[] = "constant"; +const char trailer[4096] = "push other things off of rodata page"; + +int main() +{ + REPORT_START_CMPLT; + + /* try reading/writing kernel memory */ + attempt_read((int *)0x500000); + attempt_write((int *)0x500000); + + /* try writing rodata section */ + attempt_write((int *)array); + + /* try writing text secion */ + attempt_write((int *)main); + + REPORT_END_SUCCESS; + + exit(0); +} diff --git a/410user/progs/merchant.c b/410user/progs/merchant.c new file mode 100644 index 0000000..daa5713 --- /dev/null +++ b/410user/progs/merchant.c @@ -0,0 +1,59 @@ +/** @file 410user/progs/merchant.c + * @author mpa + * @brief Tests basic functionality of exec() + * @public yes + * @for p3 + * @covers exec + * @status done + */ + +#include <syscall.h> +#include <stdio.h> +#include <string.h> +#include <simics.h> + +#define DELAY (16*1024) + +int gcc_please_do_not_optimize_too_much = 0; + +void foo() { + ++gcc_please_do_not_optimize_too_much; +} + +/* this function eats up a bunch of cpu cycles */ +void slow() { + int i; + + for (i = 0; i < DELAY; i++) foo(); +} + +int main(int argc, char **argv) { + + int tid = gettid(); + + char buf[16]; + char msg[128]; + + sprintf(buf, "%d", tid); + + /* select a message to print out */ + if (argc != 4) + sprintf(msg, + "WARNING: incorrect number of arguments - got %d, expected %d", + argc, + 4); + else if (strcmp("merchant", argv[0]) != 0 || + strcmp("13", argv[1]) != 0 || + strcmp("foo bar", argv[2]) != 0) + sprintf(msg, "WARNING: incorrect arguments"); + else if (strcmp(argv[3], buf)) + sprintf(msg, "WARNING: tid changed"); + else + sprintf(msg, "Hello!"); + + /* print message forever */ + while(1) { + slow(); + lprintf("Message from merchant #%d:\t%s", tid, msg); + } +} diff --git a/410user/progs/minclone_many.S b/410user/progs/minclone_many.S new file mode 100644 index 0000000..27c4546 --- /dev/null +++ b/410user/progs/minclone_many.S @@ -0,0 +1,177 @@ +/** + * @file minclone_many.S + * @author nwf + * @author de0u + * @brief Spawn many threads within a task: + * 128 blocks of 64 threads, with + * occasional pauses for cleanup. + * @public yes + * @for p3 + */ + +#include "410_tests.h" +#include <syscall_int.h> + +.section .rodata + +test_name: + .string "minclone_many:" +str3str: + .string "%s%s%s" +str_thread: + .string "%s: hello from tid %d in block %d" +test_start: + .string TEST_START_CMPLT +test_error: + .string TEST_END_FAIL +test_finish: + .string TEST_END_SUCCESS +test_pfx: + .string TEST_PFX + +line_fmt: + .string "%02X " + +str_T: + .string "T" +str_bang: + .string "!" +str_newline: + .string "\n" +.align 4 +/* syscall packets for print() */ +print_T_args: + .long 1 + .long str_T +print_bang_args: + .long 1 + .long str_bang +print_newline_args: + .long 1 + .long str_newline + +.section .text + +/* Created threads avoid using the original thread's stack. + * XXX Arguably better: array hosting thread stacks. + */ + +.global main +main: + pushl %ebp + movl %esp,%ebp + + /* REPORT_START_CMPLT */ + pushl $test_start + pushl $test_name + pushl $test_pfx + pushl $str3str + call lprintf + movl %ebp,%esp + + /* set_status(-17) */ + movl $-17,%esi + int $SET_STATUS_INT + + /* Engage grading-harness progress sensor */ + /* sim_fr_prog(30) */ + movl $30, %ecx + movl $SIM_FR_PROG, %ebx + xchg %bx, %bx + + movl $128, %edx /* %edx = block count */ + +block_loop: + /* printf("%02x ", block) */ + pushl %ecx + pushl %edx + pushl $line_fmt + call printf + popl %eax + popl %edx + popl %ecx + + movl $64, %ecx /* %ecx = per-block thread count */ + +thread_loop: + int $THREAD_FORK_INT + cmpl $0x0, %eax + jg parent_thread + jl error + +spawned_thread: + /* Declare progress to grading harness */ + /* sim_fr_here() */ + movl $SIM_FR_HERE, %ebx + xchg %bx, %bx + + /* print(1, "T") */ + movl $print_T_args, %esi + int $PRINT_INT + + int $VANISH_INT + +parent_thread: + decl %ecx + jne thread_loop + + /* sleep(7) -- hopefully enough for the threads to finish */ + movl $7,%esi + int $SLEEP_INT + + /* print(1, "\n") */ + movl $print_newline_args, %esi + int $PRINT_INT + + decl %edx + jne block_loop + +finish: + /* REPORT_END_SUCCESS */ + pushl $test_finish + pushl $test_name + pushl $test_pfx + pushl $str3str + call lprintf + movl %ebp,%esp + pushl $1 + pushl $test_name + call sim_update_scoreboard + movl %ebp,%esp + + /* set_status(0) */ + movl $0x0,%esi + int $SET_STATUS_INT + + int $VANISH_INT + +error: + /* print(1, "!") */ + movl $print_bang_args, %esi + int $PRINT_INT + + /* sleep(7) -- hopefully drain out broken partial block of threads */ + movl $7,%esi + int $SLEEP_INT + + /* print(1, "\n") */ + movl $print_newline_args, %esi + int $PRINT_INT + + /* REPORT_END_FAIL */ + pushl $test_error + pushl $test_name + pushl $test_pfx + pushl $str3str + call lprintf + call printf + movl $print_newline_args, %esi + int $PRINT_INT + movl %ebp,%esp + pushl $0 + pushl $test_name + call sim_update_scoreboard + movl %ebp,%esp + + int $VANISH_INT + diff --git a/410user/progs/minclone_mem.S b/410user/progs/minclone_mem.S new file mode 100644 index 0000000..0cef2f5 --- /dev/null +++ b/410user/progs/minclone_mem.S @@ -0,0 +1,78 @@ +/** @file 410user/progs/minclone_mem.S + * @author mpa + * @brief Tests sharing of memory in thread_fork + * @public yes + * @for p3 + * @covers thread_fork + * @status needswork + */ + +#include "410_tests.h" +#include "syscall_int.h" + +.global main + +test_name: + .string "minclone_mem:" +str: + .string "%s%s%s" +test_start: + .string TEST_START_CMPLT +test_pfx: + .string TEST_PFX +test_end_success: + .string TEST_END_SUCCESS + + +.comm hpvar,4,4 + +main: + pushl %ebp + movl %esp,%ebp + + pushl $test_start + pushl $test_name + pushl $test_pfx + pushl $str + call lprintf + + movl $0x0,hpvar + addl $0x4,%esp + movl $0x0,4(%esp) + + /* fork a thread */ + int $THREAD_FORK_INT + + cmpl $0x0,%eax + je child + +parent: + movl $0x172,4(%esp) /* signal child */ +loop: + cmpl $0xbacacaba,hpvar /* wait to be signaled */ + jne loop + + /* Ok, test was successful... */ + + pushl $test_end_success + pushl $test_name + pushl $test_pfx + pushl $str + call lprintf + + /* exit(0) */ + movl $0x0,%esi + int $SET_STATUS_INT + int $VANISH_INT + + leave + ret + + +child: + cmpl $0x172,4(%esp) /* wait to be signaled */ + jne child + + movl $0xbacacaba,hpvar /* signal parent */ + + int $VANISH_INT /* bye-bye */ diff --git a/410user/progs/new_pages.c b/410user/progs/new_pages.c new file mode 100644 index 0000000..749c02b --- /dev/null +++ b/410user/progs/new_pages.c @@ -0,0 +1,95 @@ +/** @file 410user/progs/new_pages.c + * @author de0u + * @brief Tests new_pages() a lot. + * @public yes + * @for p3 + * @covers new_pages + * @status done + */ + +/* Here's what we do */ +int new_stack(void); /* new_pages() into the stack */ +int new_data(void); /* new_pages() into data region */ +int lotsa_luck(void); /* new_pages() "too much" memory */ + +#include <syscall.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "410_tests.h" +#include <report.h> +#include <test.h> + +/* Yes, I mean this--see below */ +#define TEST_NAME "new_pages:" +DEF_TEST_NAME(TEST_NAME); + +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif +#define PAGE_BASE(a) (((int)(a)) & ~(PAGE_SIZE - 1)) + +int main(int argc, char *argv[]) { + int rets[3], i; + char mbuf[256]; + + REPORT_START_CMPLT; + + rets[0] = new_stack(); + rets[1] = new_data(); + rets[2] = lotsa_luck(); + + for (i = 0; i < sizeof (rets) / sizeof (rets[0]); ++i) { + if (rets[i] == 0) { + REPORT_MISC("I *want* my outs to count!!!"); /* Christine Lavin */ + report_fmt("died on %d", i); + REPORT_END_FAIL; + exit(71); + } + } + + format_end(mbuf, sizeof(mbuf), END_SUCCESS); + + exhaustion(exit_success, mbuf); + + REPORT_END_SUCCESS; + exit(0); +} + +int +new_stack(void) +{ + int answer = 42; + int ret; + + ret = new_pages((void *)PAGE_BASE((&answer)), PAGE_SIZE); + if (answer != 42) { + REPORT_MISC("My brain hurts!"); /* T.F. Gumby */ + REPORT_END_FAIL; + exit(71); + } + return (ret); +} + +int +new_data(void) +{ + int ret; + + ret = new_pages((void *)PAGE_BASE(test_name), PAGE_SIZE); + if (strcmp(test_name, TEST_NAME)) { + report_misc("new_pages() killed .data?"); + REPORT_END_FAIL; + exit(71); + } + return (ret); +} + +#define ADDR 0x40000000 +#define GIGABYTE (1024*1024*1024) + +int +lotsa_luck(void) +{ + return (new_pages((void *)ADDR, GIGABYTE)); +} diff --git a/410user/progs/new_shell.c b/410user/progs/new_shell.c new file mode 100644 index 0000000..e3a0135 --- /dev/null +++ b/410user/progs/new_shell.c @@ -0,0 +1,27 @@ +/** @file new_shell.c + * @brief This program tests the new_console() syscall by spawning a + * new shell + * + * @author Geoffrey G. Wilson (ggw) + * @author E. Chaos Golubitsky (egolubit) + * + */ +#include <syscall.h> +#include <stdio.h> + +int main() +{ + char *argvec[] = { "shell", 0} ; + + if (!(fork())) { + printf("i am thread %d; about to switch consoles\n", gettid()); + if (new_console() < 0) { + printf("failed to create new console\n"); + return(-1); + } else { + exec(argvec[0], argvec); + } + } + + return(0); +} diff --git a/410user/progs/peon.c b/410user/progs/peon.c new file mode 100644 index 0000000..2a37bb5 --- /dev/null +++ b/410user/progs/peon.c @@ -0,0 +1,35 @@ +/** @file 410user/progs/peon.c + * @author mpa + * @brief Tests exec() by launching merchant. + * @public yes + * @for p3 + * @covers exec + * @status done + */ + +#include <syscall.h> +#include <stdio.h> +#include <stddef.h> +#include <simics.h> + +int main() { + + int tid = gettid(); + + char buf[16]; + char * prog = "merchant"; + char * args[5] = { "merchant", "13", "foo bar", NULL, NULL }; + + args[3] = buf; + sprintf(buf, "%d", tid); + + lprintf("promoting peon #%d to a merchant", tid); + + if (exec(prog, args) < 0) + lprintf("ABORTING: exec returned error"); + else + lprintf("ABORTING: exec returned success"); + + /* infinite loop as exit may not be implemented */ + while(1); +} diff --git a/410user/progs/print_basic.c b/410user/progs/print_basic.c new file mode 100644 index 0000000..37c3c2b --- /dev/null +++ b/410user/progs/print_basic.c @@ -0,0 +1,27 @@ +/** @file 410user/progs/print_basic.c + * @author mpa + * @author mtomczak + * @brief Tests print(). + * @public yes + * @for p3 + * @covers print + * @status done + */ + +#include <syscall.h> +#include <stdlib.h> +#include <stdio.h> +#include "410_tests.h" + +DEF_TEST_NAME("print_basic:"); + +int main() +{ + REPORT_START_CMPLT; + if (print(13, "Hello World!\n") != 0) + REPORT_END_FAIL; + else + REPORT_END_SUCCESS; + + exit(0); +} diff --git a/410user/progs/progs.mk b/410user/progs/progs.mk new file mode 100644 index 0000000..4dc9b89 --- /dev/null +++ b/410user/progs/progs.mk @@ -0,0 +1,15 @@ +410UPROGS = $(patsubst %,$(410UDIR)/$(UPROGDIR)/%,$(410REQPROGS) $(410TESTS)) +STUUPROGS = $(patsubst %,$(STUUDIR)/$(UPROGDIR)/%,$(STUDENTREQPROGS) $(STUDENTTESTS)) +410UBINPROGS = $(patsubst %,$(410UDIR)/$(UPROGDIR)/%,$(410REQBINPROGS)) + +410UCLEANS += $(410UPROGS) $(410UBINPROGS) + +$(410UBINPROGS): %: %.bin + cp $< $@ + +ULIBS=$(410ULIBS_EARLY) $(STUULIBS_EARLY) $(410ULIBS_LATE) $(STUULIBS_LATE) +$(410UPROGS) $(EXTRA_410_PROGS): %: %.o $(CRT0) $(ULIBS) + $(LD) $(LDFLAGS) -o $@ $< $(CRT0) --start-group $(ULIBS) --end-group + +$(STUUPROGS): %: %.o $(CRT0) $(ULIBS) + $(LD) $(LDFLAGS) -o $@ $< $(CRT0) --start-group $(ULIBS) --end-group diff --git a/410user/progs/readline_basic.c b/410user/progs/readline_basic.c new file mode 100644 index 0000000..b60ebfe --- /dev/null +++ b/410user/progs/readline_basic.c @@ -0,0 +1,25 @@ +/** @file 410user/progs/readline_basic.c + * @author mpa + * @brief Tests readline() + * @public yes + * @for p3 + * @covers readline + * @status done + */ + +#include <syscall.h> +#include <stdlib.h> +#include <simics.h> +#include "410_tests.h" +#include <report.h> + +DEF_TEST_NAME("readline_basic:"); + +int main() { + char buf[100]; + report_start(START_CMPLT); + REPORT_FAILOUT_ON_ERR(magic_readline(100, buf)); + report_misc(buf); + report_end(END_SUCCESS); + exit(0); +} diff --git a/410user/progs/register_test.S b/410user/progs/register_test.S new file mode 100644 index 0000000..a45f866 --- /dev/null +++ b/410user/progs/register_test.S @@ -0,0 +1,172 @@ +/** @file 410user/progs/register_test.S + * @author mpa + * @author ctokar + * @brief Tests that registers are saved over context switches. + * @public yes + * @for p3 + * @covers ctxsw + * @status needswork + */ + +#include "410_tests.h" + +.global main + .section .rodata + +test_name: + .string "register_test:" +str: + .string "%s%s%s" +test_start: + .string TEST_START_4EVER +test_pfx: + .string TEST_PFX +test_end_fail: + .string TEST_END_FAIL + +.align 4 +eax: + + .long 0x17 +ebx: + .long 0x42 +ecx: + .long 0xffffffff +edx: + .long 0xc001d00d +esi: + .long 0x9999abcd +edi: + .long 0x12345678 +ebp: + .long 0x87654321 +esp: + .long 0xbaaaaaaa +eax2: + .long 0x20 +ebx2: + .long 0x45 +ecx2: + .long 0x01010101 +edx2: + .long 0xbeef0011 +esi2: + .long 0xfeedcafe +edi2: + .long 0x98765432 +ebp2: + .long 0x12457802 +esp2: + .long 0xabcdefab +str2: + .string "%s%sOoops: %%eax=0x%x, %%ebx=0x%x, %%ecx=0x%x, %%edx=0x%x, %%esi=0x%x, %%edi=0x%x, %%esp=0x%x, %%ebp=0x%x\n" + .text +.comm oldesp,4,4 +.comm oldebp,4,4 +.comm newesp,4,4 +.comm newebp,4,4 + +main: + movl %esp,oldesp + movl %ebp,oldebp + + movl %esp,%ebp + pushl $test_start + pushl $test_name + pushl $test_pfx + pushl $str + call lprintf + + call fork + cmp $0, %eax + je child + +parent: +.align 8 + movl eax,%eax + movl ebx,%ebx + movl ecx,%ecx + movl edx,%edx + movl esi,%esi + movl edi,%edi + movl ebp,%ebp + movl esp,%esp + +loop: + cmpl eax,%eax + jne oops + cmpl ebx,%ebx + jne oops + cmpl ecx,%ecx + jne oops + cmpl edx,%edx + jne oops + cmpl esi,%esi + jne oops + cmpl edi,%edi + jne oops + cmpl ebp,%ebp + jne oops + cmpl esp,%esp + jne oops + jmp loop + +child: +.align 8 + movl eax2,%eax + movl ebx2,%ebx + movl ecx2,%ecx + movl edx2,%edx + movl esi2,%esi + movl edi2,%edi + movl ebp2,%ebp + movl esp2,%esp + +loop2: + cmpl eax2,%eax + jne oops + cmpl ebx2,%ebx + jne oops + cmpl ecx2,%ecx + jne oops + cmpl edx2,%edx + jne oops + cmpl esi2,%esi + jne oops + cmpl edi2,%edi + jne oops + cmpl ebp2,%ebp + jne oops + cmpl esp2,%esp + jne oops + jmp loop2 + +oops: + movl %esp,newesp + movl oldesp,%esp + movl %ebp,newebp + movl oldesp,%ebp + + push newebp + push newesp + push $edi + push $esi + push $edx + push $ecx + push $ebx + push $eax + push $test_name + push $test_pfx + push $str2 + call lprintf + + push $test_end_fail + push $test_name + push $test_pfx + push $str + call lprintf + + movl oldesp,%esp + movl oldebp,%ebp + movl $0xffffffff,%eax + ret diff --git a/410user/progs/remove_pages_test1.c b/410user/progs/remove_pages_test1.c new file mode 100644 index 0000000..6c751ba --- /dev/null +++ b/410user/progs/remove_pages_test1.c @@ -0,0 +1,63 @@ +/** @file 410user/progs/remove_pages_test1.c + * @author mpa + * @brief Tests remove_pages() + * @public yes + * @for p3 + * @covers remove_pages new_pages + * @status done + */ + +#include <syscall.h> +#include <stdio.h> +#include "410_tests.h" +#include <report.h> + +#define ADDR 0x40000000 +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif + +DEF_TEST_NAME("remove_pages_test1:"); + +int main() { + int i; + int size; + int failed = 0; + + report_start(START_CMPLT); + lprintf("This test exercises remove_pages\n"); + lprintf("It assumes that new_pages works as spec\n"); + + for(size = 1; size < 50; size++) { + /* allocate pages */ + if (new_pages((void *)ADDR, size * PAGE_SIZE) != 0) { + lprintf("new_pages failed to allocated %d bytes at %x", + size * PAGE_SIZE, ADDR); + failed = 1; + } + + /* verify pages */ + for (i = 0; i < size; i++) { + if (*(int *)(ADDR + i * PAGE_SIZE) != 0) { + lprintf("allocated page not zeroed at %x", ADDR + i * PAGE_SIZE); + failed = 1; + } + *(int *)(ADDR + i * PAGE_SIZE) = i+1; + } + + /* remove pages */ + if (remove_pages((void *)ADDR) != 0) { + lprintf("remove_pages failed to remove pages at %x", ADDR); + failed = 1; + } + + } + + if (failed) { + report_end(END_FAIL); + return -1; + } + + report_end(END_SUCCESS); + return 0; +} diff --git a/410user/progs/remove_pages_test2.c b/410user/progs/remove_pages_test2.c new file mode 100644 index 0000000..d79bf2b --- /dev/null +++ b/410user/progs/remove_pages_test2.c @@ -0,0 +1,60 @@ +/** @file 410user/progs/remove_pages_test2.c + * @author mpa + * @brief Tests remove_pages() + * @public yes + * @for p3 + * @covers new_pages remove_pages + * @status done + */ + +#include <syscall.h> +#include <stdio.h> +#include "410_tests.h" +#include <report.h> + +#define ADDR 0x40000000 +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif + +DEF_TEST_NAME("remove_pages_test2:"); + +int main() { + report_start(START_ABORT); + lprintf("This test checks that remove_pages removed the pages\n"); + lprintf("It assumes that new_pages works as spec\n"); + + /* allocate a couple pages */ + if (new_pages((void *)ADDR, 5 * PAGE_SIZE) != 0) { + lprintf("new_pages failed at %x", ADDR); + report_end(END_FAIL); + return -1; + } + + if (*(int *)(ADDR + 2 * PAGE_SIZE) != 0) { + lprintf("allocated page not zeroed at %x", ADDR + 2 * PAGE_SIZE); + report_end(END_FAIL); + return -1; + } + *(int *)(ADDR + 2 * PAGE_SIZE) = 5; + + if (remove_pages((void *)ADDR) != 0) { + lprintf("remove_pages failed to remove pages at %x", ADDR); + report_end(END_FAIL); + return -1; + } + + report_misc("pages removed"); + + switch (*(int *)(ADDR + 2 * PAGE_SIZE)) { + case 5: + report_misc("pages not really removed"); + break; + + default: + report_fmt("pages still mapped, got %d", *(int *)(ADDR + 2 * PAGE_SIZE)); + break; + } + report_end(END_FAIL); + return -1; +} diff --git a/410user/progs/score.c b/410user/progs/score.c new file mode 100644 index 0000000..29ed81a --- /dev/null +++ b/410user/progs/score.c @@ -0,0 +1,146 @@ +/** @file 410user/progs/score.c + * + * @author Ryan Chen (ryanc1) + * @author Urvi Agrawal (urvia) + * + * @brief Runs batches of scoreboard tests based on flags provided in argv + * @public yes + * @for p3 + * @covers argc/argv, fork(), exec(), new_pages(), remove_pages() + * + * @bug None known + */ + +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> + +#include "syscall.h" +#include "simics.h" +#include "string.h" + +// These tests will be run if no other test suite is specified in argv. +// @covers Loading, getpid(), exec(), fork(), print() +char *default_tests[] = { + "getpid_test1", + "loader_test1", + "loader_test2", + "exec_basic", + "exec_nonexist", + "fork_test1", + "print_basic", + NULL, +}; + +// Run these tests by adding "memory" to argv. +// @covers new_pages(), remove_pages(), page fault handler, +// zeroed allocations/ZFOD +char *memory_tests[] = { + "new_pages", + "remove_pages_test1", + "mem_permissions", + NULL, +}; + +typedef struct { + char *name; + char **programs; +} TestSuite; + +// Array mapping strings potentially in argv[1] to test tables +TestSuite suites[] = { + {"memory", memory_tests}, + {NULL, default_tests}, +}; + +// You know how in kindergarten you didn't actually sleep during +// naptime so you just counted the number of tiles on the ceiling? +// No? Just me? +#define FAKE_SLEEP_DELAY 8096 +int num_tiles_gcc_please_I_want_to_live = 0; + +static void spin_delay() { + for (int i = 0; i < FAKE_SLEEP_DELAY; i++) { + ++num_tiles_gcc_please_I_want_to_live; + } +} + +// Returns 0 if x == NULL, y == NULL +// Returns some unspecified non-zero value if only one of x or y is NULL +// Otherwise, returns strcmp(x, y) +int safe_strcmp(char *x, char *y) { + if (x == NULL && y == NULL) { + return 0; + } else if (x == NULL) { + return -42; + } else if (y == NULL) { + return -42; + } else { + return strcmp(x, y); + } +} + +// Mass fork()/exec() all the tests in the named test suite. +void fork_test_suite(TestSuite *test_suite) { + if (test_suite->name == NULL) { + lprintf("score: Running default test suite."); + } else { + lprintf("score: Running test suite '%s'", test_suite->name); + } + + int program_num = 0; + while (test_suite->programs[program_num] != NULL) { + int pid = fork(); + char *testname = test_suite->programs[program_num]; + + if (pid < 0) { + lprintf("score: fork() failed while launching %s", testname); + spin_delay(); + } else if (pid == 0) { + char *args[2]; + args[0] = testname; + args[1] = NULL; + + exec(testname, args); + + lprintf("score: exec(%s) failed..?", testname); + } else { // pid > 0 + ++program_num; + } + } +} + +void run_suite(char *suite_name) { + int num_suites_loaded = sizeof(suites) / sizeof(suites[0]); + for (int i = 0; i < num_suites_loaded; i++) { + if (safe_strcmp(suite_name, suites[i].name) == 0) { + fork_test_suite(&suites[i]); + return; + } + } + + lprintf("score: test suite '%s' not found.", suite_name); +} + + +int main(int argc, char **argv) { + if (argc == 0) { // Maybe argv is not correct? + lprintf("score: argc == 0??"); + } else { + run_suite(NULL); // Always run the default suite. + if (argc >= 2) { + run_suite(argv[1]); // Additionally, run a named test suite + } + } + + // Since this test is meant to be run instead of init (before the shell is + // functional), this program must be persistent. + int sheep = 0; + while (true) { + ++sheep; + spin_delay(); + } + + lprintf("score: escaped infinite loop???"); + return -42; // Hopefully not. +} diff --git a/410user/progs/shell.c b/410user/progs/shell.c new file mode 100644 index 0000000..5546d7f --- /dev/null +++ b/410user/progs/shell.c @@ -0,0 +1,276 @@ +/** @file 410user/progs/shell.c + * @author ? + * @brief The shell. + * @public yes + * @for p2 p3 + * @covers fork exec wait set_status vanish print ls + * @status done + */ + +/* --- Since we're not calling thr_init() --- */ +/* (this is sleazy violence, *not* good form) */ +#define malloc _malloc +#define calloc _calloc +#define realloc _realloc +#define free _free + +/* --- Includes --- */ +#include <string.h> +#include <syscall.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdlib.h> + +#include <simics.h> + +/* --- Defines --- */ +#define MAX_LENGTH 1024 + + +/* --- Initialized Global Strings --- */ +char prompt[] = "[410-shell]$ "; +char startmsg[] = "Starting shell...\n"; +char exitmsg[] = "Exiting shell...\n"; +char forkerrmsg[] = "Shell: Cannot fork process.\n"; +char waitfailed[] = "wait() failed\n"; +char finished[] = "Process finished\n"; +char too_long[] = "That string is too long.\n"; +char null_check[] = "I've lost null termination!\n"; +char nothing[] = "Readline returned nothing!\n"; + +/* --- These are global only to avoid stack growth --- */ +/* (unclean, but lets the shell run before swexn() and new_pages()) */ +char buf[MAX_LENGTH]; +char *cmd_argv[MAX_LENGTH]; +char separators[4] = { ' ', '\t', '\n' }; + +static void print_ls(void); +static void sort_names(char **names, int num_entries); +static int mystical_readline(int len, char *buf); +static int console_height(void); + +/* Not all kernels support getchar(). + * + * Try to use it, but if it doesn't work fall back to readline(). + */ +static int fallback_getchar(void) +{ + char buf[2]; + + mystical_readline(2, buf); + + return (unsigned char)buf[0]; // cast prevents sign extension +} + +static int try_getchar(void) +{ + static int missing_getchar = 0; + int c; + + if (missing_getchar || (c = getchar()) < 0) { + missing_getchar = 1; + return fallback_getchar(); + } + return c; +} +#define getchar try_getchar + +/* --- Main --- */ +int +main(int argc, char *argv[]) +{ + int n; + int pid; + int res; + int j; + int ret; + + print(strlen(startmsg), startmsg); + + while(1) { + + bzero(buf, MAX_LENGTH); + print(strlen(prompt), prompt); + n = mystical_readline(MAX_LENGTH - 1, buf); + if (n == 0) { + /* Empty result; this shouldn't happen. */ + print(strlen(nothing), nothing); + continue; + } else if(n >= MAX_LENGTH) { + /* line too big -- kernel declared that it clobbered memory */ + print(strlen(too_long), too_long); + exit(-1); + } else if(buf[MAX_LENGTH - 1] != '\0') { + /* Overflow -- kernel tapdanced on random memory! */ + print(strlen(null_check), null_check); + exit(-1); + } + + buf[n] = '\0'; + j = 0; + if(!(cmd_argv[j++] = strtok(buf, separators))) { + continue; + } + if((strcmp(cmd_argv[0], "exit") == 0)) { + print(strlen(exitmsg), exitmsg); + exit(0); + } + if((strcmp(cmd_argv[0], "ls") == 0)) { + print_ls(); + continue; + } + + while((cmd_argv[j++] = strtok(NULL, separators))); + + pid = fork(); + if(pid < 0) { + print(sizeof(forkerrmsg), forkerrmsg); + continue; + } + if(pid == 0) { + exec(cmd_argv[0], cmd_argv); + exit(-1); + } + else { + if((ret = wait(&res)) < 0) { + printf("\nshell: wait on process %d failed!\n", pid); + } + else { + printf("\nshell: process %d finished with exit status %d\n", ret, res); + } + } + } /* while loop */ +} + +/* emulate the old ls() system call using readfile() */ +int ls(int size, char *buf) +{ + int i; + int num_files = 0; + int amt_read; + + amt_read = readfile(".", buf, size, 0); + if (amt_read < 0) return amt_read; + /* ls() returned failure if the buffer wasn't big enough for the + * entire listing. So if readfile() didn't return short (that is, + * there might be more), fail. */ + if (amt_read == size) return -1; + + /* Now scan through the buffer counting null terminators. + * Skip the one at the end. */ + for (i = 0; i < amt_read - 1; i++) { + if (buf[i] == '\0') { + num_files++; + } + } + + return num_files; +} + +static void print_ls() +{ + char *buf = NULL; + static int size = 16; + int num_entries; + char ** names = NULL; + char *bufptr; + int index; + int len; + + /* get the array of entries */ + buf = (char *)malloc(sizeof(char) * size); + if (buf == NULL) { + printf("Can't malloc(%d)!\n", sizeof(char) * size); + goto cleanup; + } + while ((num_entries = ls(size, buf)) < 0) { + size *= 2; + char *nbuf = (char *)realloc(buf, sizeof(char) * size); + if (nbuf == NULL) { + printf("Can't realloc(%d)!\n", sizeof(char) * size); + goto cleanup; + } else { + buf = nbuf; + } + } + + names = (char **)calloc(num_entries, sizeof(char *)); + if (names == NULL) { + printf("Can't calloc(%d)!\n", num_entries * sizeof(char *)); + goto cleanup; + } + + /* get pointers to each string in the array */ + bufptr = buf; + index = 0; + while ((len = strlen(bufptr)) > 0) { + names[index++] = bufptr; + bufptr += len + 1; + } + + sort_names(names, num_entries); + + printf("Listing the user tests\n"); + for (index = 0; index < num_entries; index++) { + if (index != 0 && index % (console_height() - 2) == 0) { + printf("Hit a key to continue\n"); + getchar(); + } + printf("%s\n", names[index]); + } + +cleanup: + if (buf) { + free(buf); + buf = NULL; + } + if (names) { + free(names); + names = NULL; + } +} + +static void sort_names(char **names, int num_entries) { + /* I invented this cool new sorting algorithm! It's really fast! */ + int swapped; + int i; + do { + swapped = 0; + for (i = 0; i < num_entries - 1; i++) { + if (strcmp(names[i], names[i+1]) > 0) { + char *tmp = names[i]; + names[i] = names[i+1]; + names[i+1] = tmp; + swapped = 1; + } + } + } while (swapped); +} + +static int mystical_readline(int len, char *buf) { + if (len <= 0) { return 0; } + + buf[0] = '\0'; + /* If we're in the test harness, this does something very special! */ + sim_call(0x04108005, buf, len); + + return (buf[0] ? strlen(buf) : readline(len, buf)); +} + +static int console_height() { + static int console_height = -1; + + if (console_height == -1) { + /* determine the height of the console */ + int curstartrow, curstartcol; + get_cursor_pos(&curstartrow, &curstartcol); + console_height = 0; + while (set_cursor_pos(console_height, 0) == 0) { + console_height++; + } + set_cursor_pos(curstartrow, curstartcol); + + } + + return console_height; +} diff --git a/410user/progs/slaughter.c b/410user/progs/slaughter.c new file mode 100644 index 0000000..9544e60 --- /dev/null +++ b/410user/progs/slaughter.c @@ -0,0 +1,144 @@ +/** @file 410user/progs/slaughter.c + * @author mtelgars + * @author nwf + * @brief Runs a lot of copies of a given test. + * @public yes + * @for p3 + * @covers fork exec wait set_status vanish + * @status done + */ + +#include <syscall.h> +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include "410_tests.h" +#include <report.h> + +DEF_TEST_NAME("slaughter:"); + +unsigned int width; +int initial_tid; +int exit_status; + +void __attribute__((noreturn)) slaughter(char **argv, unsigned int depth) +{ + int curtid = gettid(); + + report_start(START_CMPLT); + + if ( ! depth ) + { + if (exec(argv[0], argv)) + { + lprintf("=====> exec failed from %d!", curtid); + exit(-373); + } + } + else + { + unsigned int i, j, matched; + int threads[2*width]; /* not doing anything smart here yet.. */ + int status, tid; + + for (i = 0; i != 2*width; ++i) + { + if ( ! (threads[i] = fork()) ) + { + /* alternate immediate exec and slaughter */ + slaughter(argv, (i % 2) * (depth - 1)); + } + else if (threads[i] < 0) { + lprintf("=====> XXX tid %d could not fork (err=%d)!!", + curtid,threads[i]); + report_end(END_FAIL); + exit(exit_status+1); + } + else + { + lprintf("=====> Slaugher created TID %d from TID %d", + threads[i], curtid); + } + } + + for (i = 0; i != 2*width; ++i) + { + tid = wait(&status); + if ( tid < 0 ) + { + lprintf("=====> XXX Wait failed in TID %d with %d; bombing out", + curtid, tid ); + report_end(END_FAIL); + exit(exit_status+3); + } + else + { + matched = 0; + for ( j = 0; j != 2*width; ++j ) + { + if ( threads[j] == tid ) + { + matched = 1; + threads[j] = -1; + break; + } + } + if ( matched == 0 ) + { + lprintf("=====> XXX Wait returned bad TID %d to TID %d; bombing out", + tid, curtid ); + report_end(END_FAIL); + exit(exit_status+5); + } + lprintf("=====> %stid %d gave %svalid status code of %d to tid %d", + (status == exit_status) ? "" : "XXX ", + tid, (status == exit_status) ? "" : "IN", status, curtid); + if ( status != exit_status ) + { + report_end(END_FAIL); + exit(exit_status+7); + } + } + } + } + + lprintf("=====> Slaughterer %d completed", curtid); + report_end(END_SUCCESS); + exit(exit_status); +} + +int main(int argc, char *argv[]) +{ + unsigned int initial_depth; + char *default_vec[] = { "print_basic", NULL }; + char **command_vec; + + if (argc < 5) + { + printf("slaughter <recursive depth> " + "<recursive width> <exit status> <command line>\n"); + initial_depth = 2; + width = 2; + exit_status = 0; + command_vec = default_vec; + printf(" DEFAULTING TO: %d %d %d %s\n", initial_depth, width, exit_status, command_vec[0]); + } + else if ( ! (width = strtoul(argv[1], NULL, 10)) ) + { + printf(" bad recursive width\n"); + return -2; + } + else if ( ! (initial_depth = strtoul(argv[2], NULL, 10)) ) + { + printf(" bad recursive depth\n"); + return -3; + } + else + { + exit_status = strtol(argv[3], NULL, 10); + command_vec = &argv[4]; + } + + slaughter(command_vec, initial_depth); + return 0; +} diff --git a/410user/progs/sleep_test1.c b/410user/progs/sleep_test1.c new file mode 100644 index 0000000..290e87a --- /dev/null +++ b/410user/progs/sleep_test1.c @@ -0,0 +1,32 @@ +/** @file 410user/progs/sleep_test1.c + * @author zra + * @brief Sleeps for amount of time given as an argument. + * @public yes + * @for p3 + * @covers sleep + * @status done + */ + +/* Includes */ +#include <syscall.h> /* for sleep, getpid */ +#include <stdio.h> +#include <simics.h> /* for lprintf */ +#include <stdlib.h> /* for atoi, exit */ +#include "410_tests.h" +#include <report.h> + +DEF_TEST_NAME("sleep_test1:"); + +int main(int argc, char *argv[]) { + report_start(START_CMPLT); + report_misc("before sleeping"); + + if (argc == 2) + sleep( atoi( argv[1] ) ); + else + sleep( 3 + (gettid() % 27) ); + + report_misc("after sleeping"); + report_end(END_SUCCESS); + exit( 42 ); +} diff --git a/410user/progs/stack_test1.c b/410user/progs/stack_test1.c new file mode 100644 index 0000000..6b40545 --- /dev/null +++ b/410user/progs/stack_test1.c @@ -0,0 +1,47 @@ +/** @file 410user/progs/stack_test1.c + * @author efaust + * @brief Tests whether auto-stack pages are zeroed. + * @public yes + * @for p3 + * @covers autostack + * @status done + * + * Note: If we ever go back to the kernel-level autostack, we should revert + * this to the old one. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <syscall.h> +#include "410_tests.h" +#include <report.h> + +DEF_TEST_NAME("stack_test1:"); + +#define SIZE (65536) + +/* Can't you see that I am not afraid */ +void touch_me_babe(char *arr, size_t len) +{ + size_t i; + for(i = 0; i < len; i++) { + arr[i] = i; + } +} + +void do_test() +{ + char ca[SIZE]; + touch_me_babe(ca, sizeof(ca)); +} + +int main() +{ + + report_start(START_CMPLT); + + do_test(); + report_misc("stack allocation successful"); + report_end(END_SUCCESS); + exit(42); +} diff --git a/410user/progs/swexn_basic_test.c b/410user/progs/swexn_basic_test.c new file mode 100644 index 0000000..b9e2869 --- /dev/null +++ b/410user/progs/swexn_basic_test.c @@ -0,0 +1,77 @@ +/** + * @file swexn_basic_test.c + * @author bblum + * @brief Tests a simple use case for swexn + * @public yes + * @for p4 + */ + +#include <stddef.h> +#include <stdlib.h> +#include <syscall.h> +#include "410_tests.h" + +DEF_TEST_NAME("swexn_basic_test:"); + +#define STAQ_SIZE (4096) +char exn_staq[STAQ_SIZE]; +#define EXN_STAQ_TOP ((void *)((unsigned int)(&exn_staq[STAQ_SIZE-7]) & ~(sizeof (int) - 1))) + +#define GOOD_MEMORY ((void *)0x40000000) + +void handler(void *arg, ureg_t *uregs) +{ + int ret; + + REPORT_MISC("Hello from a handler"); + + if (uregs == NULL) { + REPORT_MISC("what use is a handler without a ureg pointer?"); + REPORT_END_FAIL; + exit(-1); + } + + ret = new_pages(GOOD_MEMORY, STAQ_SIZE); + if (ret < 0) { + REPORT_MISC("new_pages failed"); + REPORT_END_FAIL; + exit(-1); + } + *(int *)GOOD_MEMORY = 42; + ret = swexn(EXN_STAQ_TOP, handler, NULL, uregs); + if (ret < 0) { + REPORT_MISC("second swexn rejected"); + } else { + REPORT_MISC("restoring old position failed"); + } + REPORT_END_FAIL; + exit(-1); + return; +} + +int main() +{ + int ret; + + REPORT_START_CMPLT; + + ret = swexn(EXN_STAQ_TOP, handler, NULL, NULL); + if (ret < 0) { + REPORT_MISC("swexn call rejected"); + REPORT_END_FAIL; + exit(-1); + } + + /* Invoke handler */ + ret = *(int *)GOOD_MEMORY; + + if (ret == 0) { + REPORT_MISC("handler not run?"); + REPORT_END_FAIL; + exit(-1); + } + + TEST_PROG_PROGRESS; + REPORT_END_SUCCESS; + exit(ret); +} diff --git a/410user/progs/swexn_cookie_monster.c b/410user/progs/swexn_cookie_monster.c new file mode 100644 index 0000000..151ce25 --- /dev/null +++ b/410user/progs/swexn_cookie_monster.c @@ -0,0 +1,85 @@ +/** + * @file swexn_cookie_monster.c + * @brief Tests the correct passing of arguments to swexn handlers + * + * @author mischnal + * @for swexn p4 + * @covers swexn + * @public yes + */ + +#include <stddef.h> +#include <stdlib.h> +#include <syscall.h> + +#include "simics.h" +#include "410_tests.h" + +DEF_TEST_NAME("swexn_cookie_monster"); + +#define SWEXN_STACK_SIZE 2048 +char swexn_stack[SWEXN_STACK_SIZE]; +#define SWEXN_STACK ((void*)(swexn_stack + SWEXN_STACK_SIZE - 8)) + +void *cookies[] = {(void*)0xfeedbeef, (void*)0x8badf00d, (void*)0xbaddcafe, + (void*)0xc0ffee, (void*)0xface, (void*) 0x12345678, + (void*)42, (void*)57, (void*)2953575118U}; +int curr_cookie = 0; +int first_pass = 1; + + + +void handler(void *arg, ureg_t *uregs) +{ + int ret; + + if (cookies[curr_cookie] != arg) + { + REPORT_MISC(" Cookie incorrect"); + REPORT_END_FAIL; + exit(1); + } + + curr_cookie++; + if (curr_cookie < sizeof(cookies) / sizeof(cookies[0])) + { + ret = swexn(SWEXN_STACK, handler, cookies[curr_cookie], uregs); + if (ret < 0) + { + REPORT_MISC(" Failed to install handler"); + REPORT_END_FAIL; + exit(1); + } + } + else + { + /* Out of cookies */ + REPORT_END_SUCCESS; + exit(0); + } +} + +int main(void) +{ + int ret; + if (first_pass) + { + REPORT_START_CMPLT; + first_pass = 0; + } + + ret = swexn(SWEXN_STACK, handler, cookies[curr_cookie], NULL); + if (ret < 0) + { + REPORT_MISC(" Failed to install handler"); + REPORT_END_FAIL; + exit(1); + } + + *(volatile int *)NULL = 42; + + /* Should not get here */ + REPORT_MISC(" Something is very wrong"); + REPORT_END_FAIL; + return 1; +} diff --git a/410user/progs/swexn_dispatch.c b/410user/progs/swexn_dispatch.c new file mode 100644 index 0000000..50764e9 --- /dev/null +++ b/410user/progs/swexn_dispatch.c @@ -0,0 +1,55 @@ +/** + * @file swexn_dispatch.c + * @author bblum + * @brief Tests swexn basic function dispatch + * @public yes + * @for p4 + */ + +#include <stddef.h> +#include <stdlib.h> +#include <syscall.h> +#include "410_tests.h" + +DEF_TEST_NAME("swexn_dispatch:"); + +#define STAQ_SIZE (4096) +char exn_staq[STAQ_SIZE]; +#define EXN_STAQ_TOP ((void *)(&exn_staq[STAQ_SIZE-4])) + +#define COOKIE ((void *)0x0dd0ad9b) + +void handler(void *arg, ureg_t *uregs) +{ + REPORT_MISC("Hello from a handler"); + + if (arg != COOKIE) { + /* this fight is not worth fighting */ + REPORT_MISC("C is for cookie; it's not good enough for me..."); + REPORT_END_FAIL; + exit(-1); + } + + REPORT_END_SUCCESS; + exit(42); +} + +int main() +{ + int ret; + + REPORT_START_CMPLT; + + ret = swexn(EXN_STAQ_TOP, handler, COOKIE, NULL); + if (ret < 0) { + REPORT_MISC("swexn call rejected"); + REPORT_END_FAIL; + exit(-1); + } + + /* Invoke handler */ + ret = *(volatile int *)NULL; + REPORT_MISC("should not get here!"); + REPORT_END_FAIL; + exit(ret); +} diff --git a/410user/progs/swexn_rampage.c b/410user/progs/swexn_rampage.c new file mode 100644 index 0000000..4203e6d --- /dev/null +++ b/410user/progs/swexn_rampage.c @@ -0,0 +1,96 @@ +/** + * @file swexn_rampage.c + * @author de0u + * @brief Tests a simple use case for swexn + * @public yes + * @for p3 + */ + +#include <stddef.h> +#include <stdlib.h> +#include <syscall.h> +#include "410_tests.h" + +#define USER_MEM_START 0x01000000 +#define KERNEL_BOTTOM 0x00100000 // 1 megabyte; below there lie dragons + +#define ENOUGH 410 + +DEF_TEST_NAME("swexn_rampage:"); + +#define STAQ_SIZE (4096) +static char exn_staq[STAQ_SIZE]; +#define EXN_STAQ_TOP ((void *)(&exn_staq[STAQ_SIZE-7])) + +void install(void); +void rampage(void); +void handler(void *arg, ureg_t *uregs); + +static unsigned int *top_addr = (unsigned int *)USER_MEM_START - sizeof (unsigned int); + +static int events = 0; + +static unsigned int start_ticks; + +void install(void) +{ + int ret; + + ret = swexn(EXN_STAQ_TOP, handler, NULL, NULL); + if (ret < 0) { + REPORT_MISC("swexn call rejected"); + REPORT_END_FAIL; + exit(-1); + } +} + +void rampage(void) +{ + unsigned int *ip; + + for (ip = top_addr; ip > (unsigned int *)KERNEL_BOTTOM; ip--) + *ip = 0; + + REPORT_END_FAIL; // as if +} + +void handler(void *arg, ureg_t *uregs) +{ + if (uregs->cause != SWEXN_CAUSE_PAGEFAULT) { + report_fmt("bad cause %d", uregs->cause); + REPORT_END_FAIL; + exit(-1); + } + if (uregs->cr2 != (unsigned int) top_addr) { + report_fmt("bad addr 0x%x", uregs->cr2); + REPORT_END_FAIL; + exit(-1); + } + + TEST_PROG_PROGRESS; + + if (++events == ENOUGH) { + report_fmt("ticks %d", get_ticks() - start_ticks); + REPORT_END_SUCCESS; + exit(0); + } + + sleep(15); + + install(); + rampage(); +} + +int main() +{ + REPORT_START_CMPLT; + + start_ticks = get_ticks(); + + install(); + rampage(); + + REPORT_MISC("handler not run?"); + REPORT_END_FAIL; + exit(-1); +} diff --git a/410user/progs/swexn_regs.c b/410user/progs/swexn_regs.c new file mode 100644 index 0000000..643fb88 --- /dev/null +++ b/410user/progs/swexn_regs.c @@ -0,0 +1,65 @@ +/** + * @file swexn_regs.c + * @brief Tests a case of the validation of uregs. + * + * @author mischnal + * @for swexn p4 + * @covers swexn + * @public yes + */ + +#include <stddef.h> +#include <stdlib.h> +#include <syscall.h> + +#include "simics.h" +#include "410_tests.h" + +DEF_TEST_NAME("swexn_regs"); + +#define SWEXN_STACK_SIZE 2048 +char swexn_stack[SWEXN_STACK_SIZE]; +#define SWEXN_STACK ((void*)(swexn_stack + SWEXN_STACK_SIZE - 8)) + +#define EFLAGS_MASK 0x00003000 + + +void handler(void *arg, ureg_t *uregs) +{ + int ret; + REPORT_MISC(" In handler"); + + uregs->eflags |= EFLAGS_MASK; + + ret = swexn(SWEXN_STACK, handler, NULL, uregs); + if (ret < 0) + { + REPORT_END_SUCCESS; + exit(0); + } + else + { + REPORT_END_FAIL; + exit(1); + } +} + +int main(void) +{ + int ret; + + REPORT_START_CMPLT; + + ret = swexn(SWEXN_STACK, handler, NULL, NULL); + if (ret < 0) + { + REPORT_END_FAIL; + exit(1); + } + + *(volatile int *)NULL = 42; + + /* Should not get here */ + REPORT_END_FAIL; + return 1; +} diff --git a/410user/progs/swexn_stands_for_swextensible.c b/410user/progs/swexn_stands_for_swextensible.c new file mode 100644 index 0000000..31748ec --- /dev/null +++ b/410user/progs/swexn_stands_for_swextensible.c @@ -0,0 +1,58 @@ +/** + * @file swexn_stands_for_swextensible.c + * @author bblum + * @brief Tests what happens when the handler faults + * @public yes + * @for p4 + */ + +#include <stddef.h> +#include <stdlib.h> +#include <syscall.h> +#include "410_tests.h" + +DEF_TEST_NAME("swexn_stands_for_swextensible:"); + +#define STAQ_SIZE (4096) +char exn_staq[STAQ_SIZE]; +#define EXN_STAQ_TOP ((void *)(&exn_staq[STAQ_SIZE-11])) + +#define BAD_MEMORY ((void *)0x40000000) + +volatile int already_called = 0; + +void handler(void *arg, ureg_t *uregs) +{ + REPORT_MISC("Hello from a handler"); + if (already_called == 0) { + already_called = 1; + /* Incur another fault (in a way that won't get optimized). */ + exit(*(int *)BAD_MEMORY); + } else { + REPORT_MISC("Not supposed to get called again!"); + REPORT_END_FAIL; + exit(-1); + } + return; +} + +int main() +{ + int ret; + + REPORT_START_ABORT; + + ret = swexn(EXN_STAQ_TOP, handler, NULL, NULL); + if (ret < 0) { + REPORT_MISC("swexn call rejected"); + REPORT_END_FAIL; + exit(-1); + } + + /* Invoke handler */ + ret = *(int *)BAD_MEMORY; + + REPORT_MISC("something bad happened!"); + REPORT_END_FAIL; + exit(ret); +} diff --git a/410user/progs/swexn_uninstall_test.c b/410user/progs/swexn_uninstall_test.c new file mode 100644 index 0000000..34d898f --- /dev/null +++ b/410user/progs/swexn_uninstall_test.c @@ -0,0 +1,60 @@ +/** + * @file swexn_basic_test.c + * @author bblum + * @brief Tests uninstalling handlers + * @public yes + * @for p4 + */ + +#include <stddef.h> +#include <stdlib.h> +#include <syscall.h> +#include "410_tests.h" + +DEF_TEST_NAME("swexn_uninstall_test:"); + +#define STAQ_SIZE (4096) +char exn_staq[STAQ_SIZE]; +#define EXN_STAQ_TOP ((void *)(&exn_staq[STAQ_SIZE-8])) + +#define BAD_MEMORY ((void *)0x40000000) + +volatile int success = 0; + +void handler(void *arg, ureg_t *uregs) +{ + REPORT_MISC("Uh-oh, we weren't supposed to be called!"); + REPORT_END_FAIL; + exit(-1); + return; +} + +int main() +{ + int ret; + void (*x)() = (typeof(x))NULL; + + REPORT_START_ABORT; + + ret = swexn(EXN_STAQ_TOP, handler, NULL, NULL); + if (ret < 0) { + REPORT_MISC("swexn call rejected"); + REPORT_END_FAIL; + exit(-1); + } + + /* uninstall */ + ret = swexn(NULL, NULL, NULL, NULL); + if (ret < 0) { + REPORT_MISC("swexn call rejected (2)"); + REPORT_END_FAIL; + exit(-1); + } + + /* Invoke handler */ + success = *(int *)BAD_MEMORY; + + REPORT_MISC("D:"); + REPORT_END_FAIL; + exit(-1); +} diff --git a/410user/progs/wait_getpid.c b/410user/progs/wait_getpid.c new file mode 100644 index 0000000..825f10c --- /dev/null +++ b/410user/progs/wait_getpid.c @@ -0,0 +1,48 @@ +/** @file 410user/progs/wait_getpid.c + * @author mpa + * @brief Tests gettid()/wait()/fork() + * @public yes + * @for p3 + * @covers gettid wait fork set_status vanish + * @status done + */ + +#include <syscall.h> +#include <stdlib.h> +#include <stdio.h> +#include "410_tests.h" +#include <report.h> + +DEF_TEST_NAME("wait_getpid:"); + +int main() +{ + int pid, status; + + report_start(START_CMPLT); + + pid = fork(); + + if (pid < 0) { + report_end(END_FAIL); + exit(-1); + } + + if (pid == 0) { + pid = gettid(); + exit(pid); + report_end(END_FAIL); + } + if (wait(&status) != pid) { + report_end(END_FAIL); + exit(-1); + } + + if (status != pid) { + report_end(END_FAIL); + exit(-1); + } + + report_end(END_SUCCESS); + exit(0); +} diff --git a/410user/progs/wild_test1.c b/410user/progs/wild_test1.c new file mode 100644 index 0000000..bc11ecc --- /dev/null +++ b/410user/progs/wild_test1.c @@ -0,0 +1,31 @@ +/** @file 410user/progs/wild_test1.c + * @author zra + * @brief Tests thread death by unnatural causes. + * @public yes + * @for p2 p3 + * @covers faults + * @status done + */ + +/* Includes */ +#include <syscall.h> /* was for exit */ +#include <stdlib.h> /* for exit */ +#include <stdio.h> +#include <simics.h> /* for lprintf */ + +#include "410_tests.h" +DEF_TEST_NAME("wild_test1:"); + +/* Main */ +int main(void) +{ + int *wild = (int *)0x31337000; + + REPORT_START_ABORT; + + *wild = 0x2badd00d; + + REPORT_END_FAIL; + + exit( -1 ); +} diff --git a/410user/progs/work.c b/410user/progs/work.c new file mode 100644 index 0000000..46c34f9 --- /dev/null +++ b/410user/progs/work.c @@ -0,0 +1,58 @@ +/** @file 410user/progs/work.c + * @author acrichto + * @brief Factors some numbers in some tasks + * @public yes + * @for p4-smp + * @status done + */ + +#include <410_tests.h> +#include <stdio.h> +#include <stdlib.h> +#include <syscall.h> +#include <stdint.h> + +DEF_TEST_NAME("work:"); + +#define AMT 50 +#define MAX 8000000 + +int work(uint32_t num) { + uint32_t i; + uint32_t factors = 0; + + for (i = 1; i <= num; i++) { + if (num % i == 0) factors ++; + } + + return factors; +} + +int main() { + int ticks = get_ticks(); + int i; + int last = 0; + srand(0x1401); + + for (i = 0; i < AMT; i++) { + + int next = rand() % MAX; + int pid = fork(); + REPORT_ON_ERR(pid); + if (pid == 0) { + return work(next); + } + printf("factoring: %u\n", next); + } + print(1, ">"); + for (i = 0; i < AMT; i++) { + wait(NULL); + if (i * 79 / AMT > last) { + print(3, "\b=>"); + last++; + } + } + + printf("\nticks taken: %d\n", get_ticks() - ticks); + return 0; +} diff --git a/410user/progs/yield_desc_mkrun.c b/410user/progs/yield_desc_mkrun.c new file mode 100644 index 0000000..080689d --- /dev/null +++ b/410user/progs/yield_desc_mkrun.c @@ -0,0 +1,68 @@ +/** @file 410user/progs/yield_desc_mkrun.c + * @author mpa + * @brief Tests yield() and deschedule()/make_runnable() + * @public yes + * @for p3 + * @covers yield deschedule make_runnable fork set_status vanish + * @status done + */ + +#include <syscall.h> +#include <stdlib.h> +#include <stdio.h> +#include "410_tests.h" +#include <report.h> + +DEF_TEST_NAME("yield_desc_mkrun:"); + +int main() { + int parenttid, childtid, error; + + report_start(START_CMPLT); + + parenttid = gettid(); + childtid = fork(); + + if (childtid < 0) { + lprintf("cannot fork()"); + goto fail; + } + + if (childtid == 0) { + /* child */ + + /* Wait until the process deschedules itself */ + while(yield(parenttid) == 0) { + report_misc("parent not asleep yet"); + } + + report_misc("parent presumably asleep"); + + /* Wake parent back up */ + if((error = make_runnable(parenttid)) != 0) { + lprintf("make_runnable() failed %d in child", error); + goto fail; + } + report_misc("parent should be awake"); + } else { + /* parent */ + + int reject = 0; + if((error = deschedule(&reject)) != 0) { + lprintf("deschedule() failed %d in parent", error); + goto fail; + } + + /* wait() would be better, but we're not testing wait() here */ + yield(childtid); + yield(childtid); + yield(childtid); + report_end(END_SUCCESS); + } + + exit(0); + +fail: + report_end(END_FAIL); + exit(1); +} diff --git a/410user/user.mk b/410user/user.mk new file mode 100644 index 0000000..bd7deec --- /dev/null +++ b/410user/user.mk @@ -0,0 +1,60 @@ +################# TARGET-SPECIFIC RULES ################# + +# "You are not expected to understand this." +$(STUUDIR)/libthread/panic.o: CFLAGS+=-Wno-missing-noreturn +$(STUUDIR)/libsyscall/syscall.o: CFLAGS+=-Wno-missing-noreturn + +$(410UDIR)/exec2obj.dep: INCLUDES=$(KINCLUDES) +$(410UDIR)/exec2obj.dep: CFLAGS=-m32 -Wall -Werror + +# This wants to use the system standard library and everything. I'm not sure how this ever +# worked; probably only because of the use of -I-... +$(410UDIR)/exec2obj: $(410UDIR)/exec2obj.c + 410-gcc -m32 -I. -Wall -Werror -o $@ $^ +# $(CC) -m32 -iquote 410kern/inc -Wall -Werror -o $@ $^ +# $(CC) -m32 $(KINCLUDES) -Wall -Werror -o $@ $^ + +ifeq (1,$(DO_INCLUDE_DEPS)) +-include $(410UDIR)/exec2obj.dep +endif + +410UCLEANS+=$(410UDIR)/exec2obj $(410UDIR)/exec2obj.dep + +$(PROGS:%=$(BUILDDIR)/%) : +$(BUILDDIR)/%.strip : $(BUILDDIR)/% + strip -o $@ $< + +.INTERMEDIATE: $(PROGS:%=$(BUILDDIR)/%.strip) + +# Generate a directory listing file so the shell can implement ls +$(BUILDDIR)/__DIR_LISTING__: $(PROGS:%=$(BUILDDIR)/%.strip) \ + $(FILES:%=$(BUILDDIR)/%) + (printf "%s\0" $(sort $(PROGS) $(FILES)); printf "\0") > $(BUILDDIR)/__DIR_LISTING__ + +$(BUILDDIR)/user_apps.o: $(410UDIR)/exec2obj $(BUILDDIR)/__DIR_LISTING__ \ + $(PROGS:%=$(BUILDDIR)/%.strip) \ + $(FILES:%=$(BUILDDIR)/%) + ( cd $(BUILDDIR); \ + $(PROJROOT)/$(410UDIR)/exec2obj __DIR_LISTING__ $(PROGS) $(FILES)) | \ + $(AS) --32 -o $@ + +include $(410UDIR)/$(UPROGDIR)/progs.mk + +include $(patsubst %.a,$(410UDIR)/%/user.mk,$(410USER_LIBS_EARLY) $(410USER_LIBS_LATE)) + +################# STUDENT LIBRARY RULES ################# + +STUU_THREAD_OBJS := $(THREAD_OBJS:%=$(STUUDIR)/libthread/%) +ALL_STUUOBJS += $(STUU_THREAD_OBJS) +STUUCLEANS += $(STUUDIR)/libthread.a +$(STUUDIR)/libthread.a: $(STUU_THREAD_OBJS) + +STUU_SYSCALL_OBJS := $(SYSCALL_OBJS:%=$(STUUDIR)/libsyscall/%) +ALL_STUUOBJS += $(STUU_SYSCALL_OBJS) +STUUCLEANS += $(STUUDIR)/libsyscall.a +$(STUUDIR)/libsyscall.a: $(STUU_SYSCALL_OBJS) + +STUU_AUTOSTACK_OBJS := $(AUTOSTACK_OBJS:%=$(STUUDIR)/libautostack/%) +ALL_STUUOBJS += $(STUU_AUTOSTACK_OBJS) +STUUCLEANS += $(STUUDIR)/libautostack.a +$(STUUDIR)/libautostack.a: $(STUU_AUTOSTACK_OBJS) |
