mescc: Support rshift, have guile-mini-mes pass math test.
[mes.git] / module / mes / as-i386.mes
1 ;;; -*-scheme-*-
2
3 ;;; Mes --- Maxwell Equations of Software
4 ;;; Copyright © 2016,2017 Jan Nieuwenhuizen <janneke@gnu.org>
5 ;;;
6 ;;; This file is part of Mes.
7 ;;;
8 ;;; Mes is free software; you can redistribute it and/or modify it
9 ;;; under the terms of the GNU General Public License as published by
10 ;;; the Free Software Foundation; either version 3 of the License, or (at
11 ;;; your option) any later version.
12 ;;;
13 ;;; Mes is distributed in the hope that it will be useful, but
14 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 ;;; GNU General Public License for more details.
17 ;;;
18 ;;; You should have received a copy of the GNU General Public License
19 ;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
20
21 ;;; Commentary:
22
23 ;;; libc-i386.mes defines i386 assembly
24
25 ;;; Code:
26
27 (cond-expand
28  (guile-2)
29  (guile)
30  (mes
31   (mes-use-module (mes elf))))
32
33 (define (i386:function-preamble)
34   '(#x55                                ; push   %ebp
35     #x89 #xe5))                         ; mov    %esp,%ebp
36
37 ;; (define (i386:function-locals)
38 ;;   '(#x83 #xec #x20))               ; sub    $0x10,%esp -- 8 local vars
39
40 (define (i386:function-locals)
41   '(#x83 #xec #x40))              ; sub    $0x10,%esp -- 16 local vars
42
43 (define (i386:push-global-address o)
44   (or o push-global-address)
45   `(#x68 ,@(int->bv32 o)))              ; push  $0x<o>
46
47 (define (i386:push-global o)
48   (or o push-global)
49   `(#xa1 ,@(int->bv32 o)                ; mov    0x804a000,%eax
50          #x50))                         ; push  %eax
51
52 (define (i386:push-local n)
53   (or n push-local)
54   `(#xff #x75 ,(- 0 (* 4 n))))          ; pushl  0x<n>(%ebp)
55
56 (define (i386:push-local-address n)
57   (or n push-local-address)
58   `(#x8d #x45 ,(- 0 (* 4 n))            ; lea 0x<n>(%ebp),%eax
59          #x50))                         ; push %eax
60
61 (define (i386:push-local-de-ref n)
62   (or n push-local-de-ref)
63   `(#x8b #x45 ,(- 0 (* 4 n))            ; mov    -0x<n>(%ebp),%eax
64          #x0f #xb6 #x00                 ; movzbl (%eax),%eax
65          ;;#x0f #xbe #xc0                 ; movsbl %al,%eax ***FIXME BYTE****
66          #x50))                         ; push   %eax
67
68 (define (i386:pop-accu)
69   '(#x58))                              ; pop %eax
70
71 (define (i386:push-accu)
72   '(#x50))                              ; push %eax
73
74 (define (i386:pop-base)
75   '(#x5a))                              ; pop %edx
76
77 (define (i386:push-base)
78   '(#x52))                              ; push %edx
79
80 (define (i386:ret)
81   '(#xc9                                ; leave
82     #xc3))                              ; ret
83
84 (define (i386:accu->base)
85   '(#x89 #xc2))                         ; mov    %eax,%edx
86
87 (define (i386:accu->base-address)
88   '(#x89 #x02))                         ; mov    %eax,%(edx)
89
90 (define (i386:byte-accu->base-address)
91   '(#x88 #x02))                         ; mov    %al,%(edx)
92
93 (define (i386:accu->base-address+n n)
94   (or n accu->base-address+n)
95   `(#x89 #x42 ,n))                      ; mov    %eax,$0x<n>%(edx)
96
97 (define (i386:accu->local n)
98   (or n accu->local)
99   `(#x89 #x45 ,(- 0 (* 4 n))))          ; mov    %eax,-<0xn>(%ebp)
100
101 (define (i386:base->local n)
102   (or n base->local)
103   `(#x89 #x55 ,(- 0 (* 4 n))))          ; mov    %edx,-<0xn>(%ebp)
104
105 (define (i386:base->global n)
106   (or n base->global)
107   `(#x89 #x15 ,@(int->bv32 n)))         ; mov    %edx,0x0
108
109 (define (i386:accu->global n)
110   (or n accu->global)
111   `(#xa3 ,@(int->bv32 n)))              ; mov    %eax,0x0
112
113 (define (i386:accu->global-address n)
114   (or n accu->global-address)
115   `(#x8b #x15 ,@(int->bv32 n)           ; mov    0x<n>,%edx
116          #x89 #x02 ))                   ; mov    %eax,(%edx)
117
118 (define (i386:accu-zero?)
119   '(#x85 #xc0))                         ; cmpl   %eax,%eax
120
121 (define (i386:accu-non-zero?)
122   (append '(#x85 #xc0)                  ; cmpl   %eax,%eax
123           (i386:xor-zf)))
124
125 (define (i386:accu-shl n)
126   (or n accu:shl n)
127   `(#xc1 #xe0 ,n))                      ; shl    $0x8,%eax
128
129 (define (i386:accu<<base)
130   '(#x31 #xc9                           ; xor    %ecx,%ecx
131     #x89 #xd1                           ; mov    %edx,%ecx
132     #xd3 #xe0))                         ; shl    %cl,%eax
133
134 (define (i386:accu>>base)
135   '(#x31 #xc9                           ; xor    %ecx,%ecx
136     #x89 #xd1                           ; mov    %edx,%ecx
137     #xd3 #xe8))                         ; shr    %cl,%eax
138
139 (define (i386:accu-or-base)
140   '(#x09 #xd0))                         ; or    %edx,%eax
141
142 (define (i386:accu+accu)
143   '(#x01 #xc0))                         ; add    %eax,%eax
144
145 (define (i386:accu+base)
146   `(#x01 #xd0))                         ; add    %edx,%eax
147
148 (define (i386:accu+value v)
149   (or v accu+value)
150   `(#x05 ,@(int->bv32 v)))              ; add    %eax,%eax
151
152 (define (i386:accu-base)
153   `(#x29 #xd0))                         ; sub    %edx,%eax
154
155 (define (i386:accu*base)
156   `(#xf7 #xe2))                         ; mul    %edx
157
158 (define (i386:accu/base)
159   '(#x86 #xd3                           ; mov    %edx,%ebx
160     #x31 #xd2                           ; xor    %edx,%edx
161     #xf7 #xf3))                         ; div    %ebx
162
163 (define (i386:accu%base)
164   '(#x86 #xd3                           ; mov    %edx,%ebx
165     #x31 #xd2                           ; xor    %edx,%edx
166     #xf7 #xf3                           ; div    %ebx
167     #x89 #xd0))                         ; mov    %edx,%eax
168
169 (define (i386:base->accu)
170   '(#x89 #xd0))                         ; mov    %edx,%eax
171
172 (define (i386:local->accu n)
173   (or n local->accu)
174   `(#x8b #x45 ,(- 0 (* 4 n))))          ; mov    -<0xn>(%ebp),%eax
175
176 (define (i386:local-address->accu n)
177   (or n ladd)
178   `(#x8d #x45 ,(- 0 (* 4 n))))          ; lea 0x<n>(%ebp),%eax
179
180 (define (i386:local-ptr->accu n)
181   (or n local-ptr->accu)
182   `(#x89 #xe8                           ; mov    %ebp,%eax
183          #x83 #xc0 ,(- 0 (* 4 n))))     ; add    $0x<n>,%eax
184
185 (define (i386:byte-local->accu n)
186   (or n byte-local->accu)
187   `(#x0f #xb6 #x45 ,(- 0 (* 4 n))))     ; movzbl 0x<n>(%ebp),%eax
188
189 (define (i386:local->base n)
190   (or n local->base)
191   `(#x8b #x55 ,(- 0 (* 4 n))))          ; mov    -<0xn>(%ebp),%edx
192
193 (define (i386:local-address->base n) ;; DE-REF
194   (or n local-address->base)
195   `(#x8d #x55 ,(- 0 (* 4 n))))          ; lea    0x<n>(%ebp),%edx
196
197 (define (i386:local-ptr->base n)
198   (or n local-ptr->base)
199   `(#x89 #xea                           ; mov    %ebp,%edx
200          #x83 #xc2 ,(- 0 (* 4 n))))     ; add    $0x<n>,%edx
201
202 (define (i386:global->base n)
203   (or n global->base)
204   `(#xba ,@(int->bv32 n)))              ; mov   $<n>,%edx
205
206 (define (i386:global-address->accu n)
207   (or n global-address->accu)
208   `(#xa1 ,@(int->bv32 n)))              ; mov    0x<n>,%eax
209
210 (define (i386:global-address->base n)
211   (or n global-address->base)
212   `(#x8b #x15 ,@(int->bv32 n)))         ; mov    0x<n>,%edx
213
214 (define (i386:byte-base-mem->accu)
215   '(#x01 #xd0                           ; add    %edx,%eax
216          #x0f #xb6 #x00))               ; movzbl (%eax),%eax
217
218 (define (i386:byte-mem->accu)
219   '(#x0f #xb6 #x00))                    ; movzbl (%eax),%eax
220
221 (define (i386:byte-mem->base)
222   '(#x0f #xb6 #x10))                    ; movzbl (%eax),%edx
223
224 (define (i386:base-mem->accu)
225   '(#x01 #xd0                           ; add    %edx,%eax
226          #x8b #x00))                    ; mov    (%eax),%eax
227
228 (define (i386:mem->accu)
229   '(#x8b #x00))                         ; mov    (%eax),%eax
230
231 (define (i386:mem+n->accu n)
232   `(#x8b #x40 ,n))                      ; mov    0x<n>(%eax),%eax
233
234 (define (i386:base-mem+n->accu n)
235   (or n base-mem+n->accu)
236   `(#x01 #xd0                           ; add    %edx,%eax
237          #x8b #x40 ,n))                 ; mov    <n>(%eax),%eax
238
239 (define (i386:value->accu v)
240   (or v urg:value->accu)
241   `(#xb8 ,@(int->bv32 v)))              ; mov    $<v>,%eax
242
243 (define (i386:value->accu-address v)
244   `(#xc7 #x00 ,@(int->bv32 v)))         ; movl   $0x<v>,(%eax)
245
246 (define (i386:value->accu-address+n n v)
247   (or v urg:value->accu-address+n)
248   `(#xc7 #x40 ,n ,@(int->bv32 v)))      ; movl   $<v>,0x<n>(%eax)
249
250 (define (i386:base->accu-address)
251   '(#x89 #x10))                         ; mov    %edx,(%eax)
252
253 (define (i386:base-address->accu-address)
254   '(#x8b #x0a                           ; mov    (%edx),%ecx
255     #x89 #x08))                         ; mov    %ecx,(%eax)
256
257 (define (i386:accu+n n)
258   `(#x83 #xc0 ,n))                      ; add    $0x00,%eax
259
260 (define (i386:base+n n)
261   `(#x83 #xc2 ,n))                      ; add    $0x00,%edx
262
263 (define (i386:byte-base->accu-address)
264   '(#x88 #x10))                         ; mov    %dl,(%eax)
265
266 (define (i386:byte-base->accu-address+n n)
267   (or n byte-base->accu-address+n)
268   `(#x88 #x50 ,n))                      ; mov    %dl,0x<n>(%eax)
269
270 (define (i386:value->base v)
271   (or v urg:value->base)
272   `(#xba ,@(int->bv32 v)))              ; mov    $<v>,%edx
273
274 (define (i386:local-add n v)
275   (or n urg:local-add)
276   `(#x83 #x45 ,(- 0 (* 4 n)) ,v))       ; addl   $<v>,0x<n>(%ebp)
277
278 (define (i386:global-add n v)
279   (or n urg:global-add)
280   `(#x83 #x05 ,@(int->bv32 n) ,v))      ; addl   $<v>,0x<n>
281
282 (define (i386:global->accu o)
283   (or o urg:global->accu)
284   `(#xb8 ,@(int->bv32 o)))              ; mov    $<>,%eax
285
286 (define (i386:value->global n v)
287   (or n value->global)
288   `(#xc7 #x05 ,@(int->bv32 n)           ; movl   $<v>,(<n>)
289          ,@(int->bv32 v)))
290
291 (define (i386:value->local n v)
292   (or n value->local)
293   `(#xc7 #x45 ,(- 0 (* 4 n))            ; movl   $<v>,0x<n>(%ebp)
294          ,@(int->bv32 v)))
295
296 (define (i386:local-test n v)
297   (or n local-test)
298   `(#x83 #x7d ,(- 0 (* 4 n)) ,v))       ; cmpl   $<v>,0x<n>(%ebp)
299
300 (define (i386:call f g ta t d address n)
301   (or address urg:call)
302   `(#xe8 ,@(int->bv32 (- address 5))    ; call   relative $00
303          #x83 #xc4 ,(* n 4)))           ; add    $00,%esp
304
305 (define (i386:call-accu f g ta t d n)
306   `(,@(i386:push-accu)
307     ,@(i386:pop-accu)
308     #xff #xd0                           ; call   *%eax
309     #x83 #xc4 ,(* n 4)))                ; add    $00,%esp
310
311 (define (i386:accu-not)
312   `(#x0f #x94 #xc0                      ; sete %al
313          #x0f #xb6 #xc0))               ; movzbl %al,%eax
314
315 (define (i386:xor-accu v)
316   (or n urg:xor-accu)
317   `(#x35 ,@(int->bv32 v)))              ;xor    $0xff,%eax
318
319 (define (i386:xor-zf)
320   '(#x9f                                ; lahf   
321     #x80 #xf4 #x40                      ; xor    $0x40,%ah
322     #x9e))                              ; sahf   
323
324 (define (i386:accu-cmp-value v)
325   `(#x83 #xf8 ,v))                      ; cmp    $<v>,%eax
326
327 (define (i386:accu-test)
328   '(#x85 #xc0))                         ; test   %eax,%eax
329
330 (define (i386:Xjump n)
331   (or n urg:Xjump)
332   `(#xe9 ,@(int->bv32 (if (>= n 0) n (- n 5))))) ; jmp . + <n>
333
334 (define (i386:XXjump n)
335   (or n urg:XXjump)
336   `(#xe9 ,@(int->bv32 n)))              ; jmp . + <n>
337
338 (define (i386:Xjump-nz n)
339   (or n urg:Xjump-nz)
340   `(#x0f #x85 ,@(int->bv32 n)))         ; jnz . + <n>
341
342 (define (i386:Xjump-z n)
343   (or n urg:Xjump-z)
344   `(#x0f #x84 ,@(int->bv32 n)))         ; jz . + <n>
345
346 (define (i386:jump n) ;;FIXME: NEED THIS WEIRDNESS for t.c
347   (when (or (> n #x80) (< n #x-80))
348     (format (current-error-port) "JUMP n=~a\n" n)
349     barf)
350   `(#xeb ,(if (>= n 0) (- n 2) (- n 2)))) ; jmp <n>
351
352 (define (i386:jump-c n)
353   (when (or (> n #x80) (< n #x-80))
354     (format (current-error-port) "JUMP n=~a\n" n)
355     barf)
356   `(#x72 ,(if (>= n 0) n (- n 2))))     ; jc <n>
357
358 (define (i386:jump-cz n)
359   (when (or (> n #x80) (< n #x-80))
360     (format (current-error-port) "JUMP n=~a\n" n)
361     barf)
362   `(#x76 ,(if (>= n 0) n (- n 2))))     ; jbe <n>
363
364 (define (i386:jump-ncz n)
365   (when (or (> n #x80) (< n #x-80))
366     (format (current-error-port) "JUMP-ncz n=~a\n" n)
367     barf)
368   `(#x77 ,(if (>= n 0) n (- n 2))))     ; ja <n>
369
370 (define (i386:jump-nc n)
371   (when (or (> n #x80) (< n #x-80))
372     (format (current-error-port) "JUMP-nc n=~a\n" n)
373     barf)
374   `(#x73 ,(if (>= n 0) n (- n 2))))     ; jnc <n>
375
376 ;; unsigned
377 (define (i386:Xjump-nc n)
378   (or n urg:Xjump-nc)
379   `(#x0f #x83 ,@(int->bv32 n)))         ; jnc <n>
380
381 ;; unsigned
382 (define (i386:Xjump-ncz n)
383   (or n urg:Xjump-ncz)
384   `(#x0f #x87 ,@(int->bv32 n)))         ; ja <n>
385
386 ;; unsigned
387 ;; (define (i386:Xjump-c n)
388 ;;   (or n urg:Xjump-c)
389 ;;   `(#x0f #x82 ,@(int->bv32 n)))     ; jc <n>
390
391 ;; unsigned
392 ;; (define (i386:Xjump-cz n)
393 ;;   (or n urg:Xjump-cz)
394 ;;   `(#x0f #x86 ,@(int->bv32 n)))         ; jbe <n>
395
396 ;; signed
397 (define (i386:Xjump-g n)
398   (or n urg:Xjump-g)
399   `(#x0f #x8f ,@(int->bv32 n)))         ; jg/jnle <n>
400
401 ;; signed
402 (define (i386:Xjump-ge n)
403   (or n urg:Xjump-ge)
404   `(#x0f #x8d ,@(int->bv32 n)))         ; jge/jnl <n>
405
406 ;; ;; signed
407 ;; (define (i386:Xjump-l n)
408 ;;   (or n urg:Xjump-l)
409 ;;   `(#x0f #x8c ,@(int->bv32 n)))         ; jl/jnge <n>
410
411 ;; ;; signed
412 ;; (define (i386:Xjump-le n)
413 ;;   (or n urg:Xjump-le)
414 ;;   `(#x0f #x8e ,@(int->bv32 n)))         ; jle/jgn <n>
415
416 (define (i386:jump-z n)
417   (when (or (> n #x80) (< n #x-80))
418     (format (current-error-port) "JUMP-z n=~a\n" n)
419     barf)
420   `(#x74 ,(if (>= n 0) n (- n 2))))     ; jz <n>
421
422 (define (i386:jump-nz n)
423   (when (or (> n #x80) (< n #x-80))
424     (format (current-error-port) "JUMP-nz n=~a\n" n)
425     barf)
426   `(#x75 ,(if (>= n 0) n (- n 2))))     ; jnz <n>
427
428 (define (i386:test-jump-z n)
429   (when (or (> n #x80) (< n #x-80))
430     (format (current-error-port) "JUMP-z n=~a\n" n)
431     barf)
432   `(#x85 #xc0                           ; test   %eax,%eax
433     #x74 ,(if (>= n 0) n (- n 4))))     ; jz <n>
434
435 (define (i386:jump-byte-nz n)
436   (when (or (> n #x80) (< n #x-80))
437     (format (current-error-port) "JUMP-byte-nz n=~a\n" n)
438     barf)
439   `(#x84 #xc0                           ; test   %al,%al
440     #x75 ,(if (>= n 0) n (- n 4))))     ; jne <n>
441
442 (define (i386:jump-byte-z n)
443   (when (or (> n #x80) (< n #x-80))
444     (format (current-error-port) "JUMP-byte-z n=~a\n" n)
445     barf)
446   `(#x84 #xc0                           ; test   %al,%al
447     #x74 ,(if (>= n 0) n (- n 4))))     ; jne <n>
448
449 (define (i386:byte-test-base)
450   `(#x38 #xc2))                         ; cmp    %al,%dl
451
452 (define (i386:test-base)
453   `(#x39 #xd0))                         ; cmp    %edx,%eax
454
455 (define (i386:byte-sub-base)
456   `(#x28 #xd0))                         ; sub    %dl,%al
457
458 (define (i386:byte-base-sub)
459   `(#x28 #xd0))                         ; sub    %al,%dl
460
461 (define (i386:sub-base)
462   `(#x29 #xd0))                         ; sub    %edx,%eax
463
464 (define (i386:base-sub)
465   `(#x29 #xc2))                         ; sub    %eax,%edx
466