-
Notifications
You must be signed in to change notification settings - Fork 2
/
header.asm
188 lines (146 loc) · 4.01 KB
/
header.asm
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
;;; chainlance asm source -*- mode: nasm -*-
BITS 64
SECTION .text
;;; Symbolic names for fixed registers
%define rTapeSize rdx
%define rTapeSized edx
%define rTapeSizeb dl
%define rTapeA rbx
%define rTapeB rcx
%define rTapeAb bl
%define rTapeBb cl
%define rRepAd r8d
%define rRepBd r9d
%define rRepSA r10
%define rRepSB r11
%define rSaveIP r12
%define rCell2 r13b
%define rTapeBase r14
%define rCycles r15
%define rCyclesd r15d
;;; Top-level logic for BF Joust matches
%define MAXCYCLES 100000
%define MINTAPE 10
%define MAXTAPE 30
global main
main:
;; miscellaneous initialization
mov rbp, rsp
cld ; make stosb and such always advance
xor esi, esi ; sum of wins for progA
;; run through all tape sizes with progA vs progB
xor rTapeSized, rTapeSized
mov rTapeSizeb, MINTAPE
loop1: lea rSaveIP, [rel progB]
call run
inc rTapeSizeb
cmp rTapeSizeb, MAXTAPE
jbe loop1
;; run through all tape sizes with progA vs progB2 (reverse polarity)
xor rTapeSized, rTapeSized
mov rTapeSizeb, MINTAPE
loop2: lea rSaveIP, [rel progB2]
call run
inc rTapeSizeb
cmp rTapeSizeb, MAXTAPE
jbe loop2
;; all done, return the result (-42 .. 42 for tapes 10 .. 30)
mov eax, esi
ret
;;; Single-match execution and initialization
run: ;; runs a single match
;; rSaveIP should be set to either progB or progB2
;; rTapeSize should be set to the proper tape size
;; initialize tape for tape of rTapeSize bytes
;; also sets rTapeBase, rTapeA, rTapeB, rCell2
xor eax, eax
lea rdi, [rel tape]
mov rTapeBase, rdi ; save start of tape
mov ecx, rTapeSized
rep stosb ; tape[0 .. size-1] = 0
xor rTapeA, rTapeA ; tape pointer for A = 0 = left end
lea rTapeB, [rTapeA+rTapeSize-1] ; tape pointer for B = size-1 = right end
mov al, 128
mov [rTapeBase], al ; tape[0] = flagA = 128
mov [rTapeBase+rTapeB], al ; tape[size-1] = flagB = 128
mov rCell2, al ; copy of tape[B] for the first cycle
;; initialize rep counter stack
%if MAXREPS > 1
lea rRepSA, [rel repStackA]
lea rRepSB, [rel repStackB]
%endif
;; start executing this round
mov rCyclesd, MAXCYCLES ; initialize cycle counter
xor edi, edi ; used for "death flags"
runit: jmp progA
;;; Helper macros and snippets for the compiled code
;; context switch ProgA -> ProgB
%macro CTX_ProgA 0
lea rax, [rel %%next]
xchg rax, rSaveIP
jmp (rax)
%%next:
%endmacro
;; context switch ProgB -> ProgA
%macro CTX_ProgB 0
lea rax, [rel %%next]
jmp nextcycle
%%next:
%endmacro
;; end-of-cycle code
nextcycle:
cmp byte [rTapeBase], 0
jz .flagA ; A's flag is zero
btr edi, 1 ; A's flag is nonzero, clear flag
.testB: cmp byte [rTapeBase + rTapeSize - 1], 0
jz .flagB ; B's flag is zero
btr edi, 2 ; B's flag is nonzero, clear flag
.cont: bt edi, 0
jc .winB ; A totally dead, B wins
dec rCycles
jz tie ; tie if out of cycles
mov rCell2, [rTapeBase + rTapeB] ; save a copy for ProgB [ check
xchg rax, rSaveIP
jmp (rax)
.flagA:
bts edi, 1 ; ensure the zero gets flagged
jnc .testB ; first offense, let live and test B
bts edi, 0 ; second offense, flag totally dead
jmp .testB ; test B in case of ties
.flagB:
bts edi, 2 ; make sure it gets flagged
jnc .cont ; first offense, let live
bt edi, 0
jc tie ; A also dead. so tie
inc esi
ret ; A wins (esi +1)
.winB:
dec esi
ret ; B wins (esi -1)
;; A fell of the tape (middle of cycle, must wait for tie)
fallA:
bts edi, 0 ; flag A as totally dead
CTX_ProgA ; let B run to check for tie
;; B fell of the tape (end of cycle, can decide)
fallB:
bt edi, 0
jc tie ; A also totally dead, tie
cmp byte [rTapeBase], 0
jnz .notie ; A known to be alive, A wins
bt edi, 1
jc tie ; A dead by flag now, tie
.notie: inc esi
ret ; A wind (esi +1)
;; in case of a tie
tie: ret ; tie (no change in esi)
;;; Statically allocated memory for tape and such
SECTION .data
tape: times 30 db 0
%if MAXREPS > 1
repStackA:
times MAXREPS-1 dd 0
repStackB:
times MAXREPS-1 dd 0
%endif
SECTION .text
;;; Program code below