summaryrefslogtreecommitdiff
path: root/src/x64.asm
blob: 89351f2cfb367d83d7192b77e1c8347b81fd4f46 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
%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