%ifdef _X64_ [BITS 64] [SEGMENT .data] [EXTERN g_VectorDelta] [EXTERN g_PieceData] %ifdef OSX ;;; Note: The reason for this OSX stuff is that there is a bug in the mac ;;; version of nasm. See comments in data.c for more details. [GLOBAL g_NasmVectorDelta] [GLOBAL _g_NasmVectorDelta] g_NasmVectorDelta: _g_NasmVectorDelta: alignb 32, db 0 times 256 * 4 db 0 [GLOBAL g_NasmPieceData] [GLOBAL _g_NasmPieceData] g_NasmPieceData: _g_NasmPieceData: alignb 32, db 0 times 4 * 4 * 8 db 0 %else [EXTERN g_VectorDelta] [EXTERN g_PieceData] %endif [SEGMENT .text] %ifndef CROUTINES [GLOBAL LastBit] [GLOBAL _LastBit] ;; ;; ULONGLONG CDECL ;; LastBit(BITBOARD bb) ;; LastBit: _LastBit: bsr rax, rdi jnz .found xor rax, rax ret .found: add rax, 1 ret int 3 [GLOBAL FirstBit] [GLOBAL _FirstBit] ;; ;; ULONGLONG CDECL ;; FirstBit(BITBOARD bb) ;; FirstBit: _FirstBit: bsf rax, rdi jnz .found xor rax, rax ret .found: add rax, 1 ret int 3 [GLOBAL CountBits] [GLOBAL _CountBits] ;; ;; ULONGLONG CDECL ;; CountBits(BITBOARD bb) ;; CountBits: _CountBits: xor rax, rax mov rcx, rdi test rcx, rcx jz .done .again: add rax, 1 mov rdx, rcx sub rdx, 1 and rcx, rdx jnz .again .done: ret int 3 [GLOBAL GetAttacks] [GLOBAL _GetAttacks] db 43h,30h,50h,56h,72h,31h,47h,34h,54h,20h,32h,30h,30h db 36h,20h,53h,63h,30h,74h,74h,20h,47h,61h,73h,63h,34h iDelta dd -17 dd +15 ;; [rbp-0x8] is the saved rbx from the "push rbx" in the prologue below; ;; locals must start below that, not alias it. %define pOldList qword [rbp-0x10] %define c dword [rbp-0x14] %define x dword [rbp-0x18] %define cSquareSave dword [rbp-0x1C] %define uSideSave dword [rbp-0x20] %define _cNonPawns 0x478 %define _uNonPawnCount 0x500 %define _rgSquare 0x0 ;; ;; void CDECL (SysV AMD64 ABI) ;; GetAttacks(SEE_LIST *pList, ; rdi ;; POSITION *pos, ; rsi ;; COOR cSquare, ; edx ;; ULONG uSide) ; ecx ;; ;; NOTE: a square (COOR) is always >= 0, but a square-minus- ;; square delta is not. Any such delta must be sign-extended ;; into a 64-bit register (movsxd) before being used as a ;; scaled memory index: using the raw 32-bit register zero- ;; extends it into a huge positive 64-bit value instead of the ;; intended negative offset. This is the same bug that turned ;; up in the C DISTANCE macro -- see chess.h. ;; GetAttacks: _GetAttacks: push rbp mov rbp, rsp push rbx sub rsp, 0x20 mov cSquareSave, edx mov uSideSave, ecx mov pOldList, rdi ; pOldList = pList mov dword [rdi], 0 ; pList->uCount = 0 add rdi, 4 ; rdi = &pList->data[0] ;; ebx = c = cSquare + iDelta[uSide] movsxd rax, uSideSave mov ebx, [iDelta+rax*4] add ebx, cSquareSave ;; ecx = pPawn = BLACK_PAWN | uColor mov ecx, uSideSave or ecx, 2 ;; ;; Check the pawns ;; test ebx, 0x88 jnz .try_other_pawn movsxd rax, ebx mov eax, dword [rsi+rax*8+_rgSquare] cmp eax, ecx jne .try_other_pawn mov rax, pOldList mov dword [rax], 1 mov dword [rdi], ecx mov dword [rdi+4], ebx mov dword [rdi+8], 100 add rdi, 12 .try_other_pawn: add ebx, 2 test ebx, 0x88 jnz .done_pawns movsxd rax, ebx mov eax, dword [rsi+rax*8+_rgSquare] cmp eax, ecx jne .done_pawns mov dword [rdi], ecx mov dword [rdi+4], ebx mov dword [rdi+8], 100 mov rax, pOldList add rdi, 12 add dword [rax], 1 .done_pawns: ;; ;; Do pieces ;; ;; x = pos->uNonPawnCount[uSide][0] mov eax, uSideSave shl eax, 5 ; uSide * 32 movsxd rax, eax mov ecx, dword [rsi+rax+_uNonPawnCount] mov x, ecx .loop_continue: mov ecx, x sub ecx, 1 cmp ecx, 0 jl near .done mov x, ecx ;; eax = c = pos->cNonPawns[uSide][x] mov eax, uSideSave shl eax, 4 add eax, ecx ; eax = uSide*16 + x movsxd rax, eax mov eax, dword [rsi+rax*4+_cNonPawns] mov c, eax ;; ecx = p = pos->pSquare[c] movsxd rax, eax mov ecx, dword [rsi+rax*8+_rgSquare] ;; r8 = iIndex = c - cSquare (must stay signed) sub eax, cSquareSave movsxd r8, eax ;; ;; If there is no way for that kind of piece to get to this ;; square then keep looking. ;; mov ebx, 1 mov r9d, ecx ; r9 = p, survives to .nothing_blocks shr ecx, 1 shl ebx, cl test byte [g_VectorDelta+r8*4+512], bl jz .loop_continue ;; if (IS_KNIGHT_OR_KING(p)) goto nothing_blocks and ecx, 3 cmp ecx, 2 mov ecx, c je .nothing_blocks ;; ;; Not a knight or king. Check to see if there is a piece in ;; the path from cSquare to c that blocks the attack. ;; movsx ebx, byte [g_VectorDelta+r8*4+515] mov eax, cSquareSave .block_loop: add eax, ebx cmp eax, ecx je .nothing_blocks movsxd rdx, eax cmp dword [rsi+rdx*8], 0 jne .loop_continue jmp .block_loop .nothing_blocks: mov dword [rdi], r9d mov dword [rdi+4], ecx ;; index into g_PieceData: sizeof(PIECE_DATA) is 24 on x64 (not ;; 16, as on x86) because its trailing "CHAR *szName" widens ;; from 4 to 8 bytes and pads the struct to 8-byte alignment. mov ecx, r9d shr ecx, 1 imul ecx, ecx, 24 movsxd rcx, ecx mov ebx, dword [g_PieceData+rcx] mov dword [rdi+8], ebx mov rax, pOldList add rdi, 12 add dword [rax], 1 jmp .loop_continue .done: add rsp, 0x20 pop rbx pop rbp ret %endif ; !CROUTINES [GLOBAL LockCompareExchange] [GLOBAL _LockCompareExchange] ;; ;; ULONG CDECL ;; LockCompareExchange(void *dest, ; rdi (SysV AMD64 ABI) ;; ULONG exch, ; esi ;; ULONG comp) ; edx ;; LockCompareExchange: _LockCompareExchange: mov eax, edx ; comp -> eax (cmpxchg's implicit compare reg) mov rcx, rdi ; dest pointer -> rcx lock cmpxchg dword [rcx], esi ret int 3 [GLOBAL LockIncrement] [GLOBAL _LockIncrement] ;; ;; ULONG CDECL ;; LockIncrement(ULONG *pDest) ; rdi (SysV AMD64 ABI) ;; LockIncrement: _LockIncrement: mov rcx, rdi mov eax, 1 lock xadd [rcx], eax add eax, 1 ret int 3 [GLOBAL LockDecrement] [GLOBAL _LockDecrement] ;; ;; ULONG CDECL ;; LockDecrement(ULONG *pDest) ; rdi (SysV AMD64 ABI) ;; LockDecrement: _LockDecrement: mov rcx, rdi mov eax, -1 lock xadd [rcx], eax add eax, -1 ret int 3 %endif ; X64