mes/module/mes/as-i386.mes

383 lines
13 KiB
Scheme

;;; -*-scheme-*-
;;; Mes --- Maxwell Equations of Software
;;; Copyright © 2016,2017 Jan Nieuwenhuizen <janneke@gnu.org>
;;;
;;; This file is part of Mes.
;;;
;;; Mes is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or (at
;;; your option) any later version.
;;;
;;; Mes 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 General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with Mes. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;; as-i386.mes defines i386 assembly
;;; Code:
(cond-expand
(guile-2)
(guile)
(mes
(mes-use-module (mes as))))
(define (i386:function-preamble)
'(("push___%ebp") ; push %ebp
("mov____%esp,%ebp"))) ; mov %esp,%ebp;
(define (i386:function-locals)
'(("sub____%esp,$i8" (#:immediate1 #x40)))) ; sub %esp,$0x40 # 16 local vars
(define (i386:push-label label)
`(("push___$i32" (#:address ,label)))) ; push $0x<label>
(define (i386:push-label-mem label)
`(("mov____0x32,%eax" (#:address ,label)) ; mov 0x804a000,%eax
("push___%eax"))) ; push %eax
(define (i386:push-local n)
(or n (error "invalid value: push-local: " n))
`(("push___0x8(%ebp)" (#:immediate1 ,(- 0 (* 4 n)))))) ; pushl 0x<n>(%ebp)
(define (i386:push-local-address n)
(or n (error "invalid value: push-local-address: " n))
`(("lea____0x8(%ebp),%eax" (#:immediate1 ,(- 0 (* 4 n)))) ; lea 0x<n>(%ebp),%eax
("push___%eax"))) ; push %eax
(define (i386:push-byte-local-de-ref n)
(or n (error "invalid value: push-byte-local-de-ref: " n))
`(("mov____0x8(%ebp),%eax" (#:immediate1 ,(- 0 (* 4 n)))) ; mov -0x<n>(%ebp),%eax
("movzbl_(%eax),%eax") ; movzbl (%eax),%eax
("push___%eax"))) ; push %eax
(define (i386:push-byte-local-de-de-ref n)
(or n (error "invalid value: push-byte-local-de-de-ref: " n))
`(("mov____0x8(%ebp),%eax" (#:immediate1 ,(- 0 (* 4 n)))) ; mov -0x<n>(%ebp),%eax
("mov____(%eax),%eax") ; mov (%eax),%eax
("movzbl_(%eax),%eax") ; movzbl (%eax),%eax
("push___%eax")))
(define (i386:push-local-de-ref n)
(or n (error "invalid value: push-byte-local-de-ref: " n))
`(("mov____0x8(%ebp),%eax" (#:immediate1 ,(- 0 (* 4 n)))) ; mov -0x<n>(%ebp),%eax
("mov____(%eax),%eax") ; mov (%eax),%eax
("push___%eax"))) ; push %eax
(define (i386:pop-accu)
'(("pop____%eax"))) ; pop %eax
(define (i386:push-accu)
'(("push___%eax"))) ; push %eax
(define (i386:pop-base)
'(("pop____%edx"))) ; pop %edx
(define (i386:push-base)
'(("push___%edx"))) ; push %edx
(define (i386:ret)
'(("leave") ; leave
("ret"))) ; ret
(define (i386:accu->base)
'(("mov____%eax,%edx"))) ; mov %eax,%edx
(define (i386:accu->base-address)
'(("mov____%eax,(%edx)"))) ; mov %eax,(%edx)
(define (i386:byte-accu->base-address)
'(("mov____%al,(%edx)"))) ; mov %al,(%edx)
(define (i386:accu->base-address+n n)
(or n (error "invalid value: accu->base-address+n: " n))
`(("mov____%eax,0x8(%edx)" (#:immediate1 ,n)))) ; mov %eax,$0x<n>%(edx)
(define (i386:accu->local n)
(or n (error "invalid value: accu->local: " n))
`(("mov____%eax,0x8(%ebp)" (#:immediate1 ,(- 0 (* 4 n)))))) ; mov %eax,-<0xn>(%ebp)
;; (define (i386:accu->local-address n)
;; (or n (error "invalid value: accu->local: " n))
;; `(#x89 #x45 ,(- 0 (* 4 n)))) ; mov %eax,-<0xn>(%ebp)
(define (i386:base->local n)
(or n (error "invalid value: base->local: " n))
`(("mov____%edx,0x8(%ebp)" ,(- 0 (* 4 n))))) ; mov %edx,-<0xn>(%ebp)
(define (i386:accu->label label)
`(("mov____%eax,0x32" (#:address ,label)))) ; mov %eax,0x<label>
(define (i386:accu-zero?)
'(("test___%eax,%eax")))
(define (i386:accu-shl n)
(or n (error "invalid value: accu:shl n: " n))
`(("shl____$i8,%eax" (#:immediate1 ,n)))) ; shl $0x8,%eax
(define (i386:accu<<base)
'(("xor____%ecx,%ecx") ; xor %ecx,%ecx
("mov____%edx,%ecx") ; mov %edx,%ecx
("shl____%cl,%eax"))) ; shl %cl,%eax
(define (i386:accu>>base)
'(("xor____%ecx,%ecx") ; xor %ecx,%ecx
("mov____%edx,%ecx") ; mov %edx,%ecx
("shr____%cl,%eax"))) ; shr %cl,%eax
(define (i386:accu-or-base)
'(("or_____%edx,%eax"))) ; or %edx,%eax
(define (i386:accu-and-base)
'(("and____%edx,%eax"))) ; and %edx,%eax
(define (i386:accu-xor-base)
'(("xor____%edx,%eax"))) ; xor %edx,%eax
(define (i386:accu+accu)
'(("add____%eax,%eax"))) ; add %eax,%eax
(define (i386:accu+base)
`(("add____%edx,%eax"))) ; add %edx,%eax
(define (i386:accu+value v)
(or v (error "invalid value: accu+value: " v))
`(("add____$i32,%eax" (#:immediate ,v)))) ; add %eax,$
(define (i386:accu-base)
`(("sub____%edx,%eax"))) ; sub %edx,%eax
(define (i386:accu*base)
`(("mul____%edx"))) ; mul %edx
(define (i386:accu/base)
'(("mov____%edx,%ebx") ; mov %edx,%ebx
("xor____%edx,%edx") ; xor %edx,%edx
("div____%ebx"))) ; div %ebx
(define (i386:accu%base)
'(("mov____%edx,%ebx") ; mov %edx,%ebx
("xor____%edx,%edx") ; xor %edx,%edx
("div____%ebx") ; div %ebx
("mov____%edx,%eax"))) ; mov %edx,%eax
(define (i386:base->accu)
'(("mov____%edx,%eax"))) ; mov %edx,%eax
(define (i386:local->accu n)
(or n (error "invalid value: local->accu: " n))
`(("mov____0x8(%ebp),%eax" (#:immediate1 ,(- 0 (* 4 n)))))) ; mov -<0xn>(%ebp),%eax
(define (i386:local-address->accu n)
(or n (error "invalid value: ladd: " n))
`(("lea____0x8(%ebp),%eax" (#:immediate1 ,(- 0 (* 4 n)))))) ; lea 0x<n>(%ebp),%eax
(define (i386:local-ptr->accu n)
(or n (error "invalid value: local-ptr->accu: " n))
`(("mov____%ebp,%eax") ; mov %ebp,%eax
("add____$i8,%eax" (#:immediate1 ,(- 0 (* 4 n)))))) ; add $0x<n>,%eax
(define (i386:byte-local->accu n)
(or n (error "invalid value: byte-local->accu: " n))
`(("movzbl_0x8(%ebp),%eax" (#:immediate1 ,(- 0 (* 4 n)))))) ; movzbl 0x<n>(%ebp),%eax
(define (i386:byte-local->base n)
(or n (error "invalid value: byte-local->base: " n))
`(("movzbl_0x8(%ebp),%edx" (#:immediate1 ,(- 0 (* 4 n)))))) ; movzbl 0x<n>(%ebp),%edx
(define (i386:local->base n)
(or n (error "invalid value: local->base: " n))
`(("mov____0x8(%ebp),%edx" (#:immediate1 ,(- 0 (* 4 n)))))) ; mov -<0xn>(%ebp),%edx
(define (i386:local-address->base n) ;; DE-REF
(or n (error "invalid value: local-address->base: " n))
`(("lea____0x8(%ebp),%edx" (#:immediate1 ,(- 0 (* 4 n)))))) ; lea 0x<n>(%ebp),%edx
(define (i386:local-ptr->base n)
(or n (error "invalid value: local-ptr->base: " n))
`(("mov____%ebp,%edx") ; mov %ebp,%edx
("add____$i8,%edx" (#:immediate1 ,(- 0 (* 4 n)))))) ; add $0x<n>,%edx
(define (i386:label->accu label)
`(("mov____$i32,%eax" (#:address ,label)))) ; mov $<n>,%eax
(define (i386:label->base label)
`(("mov____$i32,%edx" (#:address ,label)))) ; mov $<n>,%edx
(define (i386:label-mem->accu label)
`(("mov____0x32,%eax" (#:address ,label)))) ; mov 0x<n>,%eax
(define (i386:label-mem->base label)
`(("mov____0x32,%edx" (#:address ,label)))) ; mov 0x<n>,%edx
(define (i386:label-mem-add label v)
`(("add____$i8,0x32" (#:address ,label) (#:immediate1 ,v)))) ; addl $<v>,0x<n>
(define (i386:byte-base-mem->accu)
'(("add____%edx,%eax") ; add %edx,%eax
("movzbl_(%eax),%eax"))) ; movzbl (%eax),%eax
(define (i386:byte-mem->accu)
'(("movzbl_(%eax),%eax"))) ; movzbl (%eax),%eax
(define (i386:byte-mem->base)
'(("movzbl_(%eax),%edx"))) ; movzbl (%eax),%edx
(define (i386:base-mem->accu)
'(("add___%edx,%eax") ; add %edx,%eax
("mov____(%eax),%eax"))) ; mov (%eax),%eax
(define (i386:mem->accu)
'(("mov____(%eax),%eax"))) ; mov (%eax),%eax
(define (i386:mem+n->accu n)
`(("mov____0x8(%eax),%eax" (#:immediate1 ,n)))) ; mov 0x<n>(%eax),%eax
(define (i386:base-mem+n->accu n)
(or n (error "invalid value: base-mem+n->accu: " n))
`(("add___%edx,%eax") ; add %edx,%eax
("mov____0x8(%eax),%eax" (#:immediate1 ,n)))) ; mov <n>(%eax),%eax
(define (i386:value->accu v)
(or v (error "invalid value: i386:value->accu: " v))
`(("mov____$i32,%eax" (#:immediate ,v)))) ; mov $<v>,%eax
(define (i386:value->accu-address v)
`(("mov____$i32,(%eax)" (#:immediate ,v)))) ; movl $0x<v>,(%eax)
(define (i386:value->accu-address+n n v)
(or v (error "invalid value: i386:value->accu-address+n: " v))
`(("mov____$i32,0x8(%eax)" (#:immediate1 ,n) (#:immediate ,v)))) ; movl $<v>,0x<n>(%eax)
(define (i386:base->accu-address)
'(("mov____%edx,%(eax)"))) ; mov %edx,(%eax)
(define (i386:base-address->accu-address)
'(("mov____(%edx),%ecx") ; mov (%edx),%ecx
("mov____%ecx,%(eax)"))) ; mov %ecx,(%eax)
(define (i386:accu+n n)
`(("add____$i8,%eax" (#:immediate1 ,n)))) ; add $0x00,%eax
(define (i386:base+n n)
`(("add____$i8,%edx" (#:immediate1 ,n)))) ; add $0x00,%edx
(define (i386:byte-base->accu-address)
'(("mov____%dl,(%eax)"))) ; mov %dl,(%eax)
(define (i386:byte-base->accu-address+n n)
(or n (error "invalid value: byte-base->accu-address+n: " n))
`(("mov____%dl,0x8(%eax)" (#:immediate1 ,n)))) ; mov %dl,0x<n>(%eax)
(define (i386:value->base v)
(or v (error "invalid value: i386:value->base: " v))
`(("mov____$i32,%edx" (#:immediate ,v)))) ; mov $<v>,%edx
(define (i386:local-add n v)
(or n (error "invalid value: i386:local-add: " n))
`(("add____$i8,0x8(%ebp)" (#:immediate1 ,(- 0 (* 4 n))) (#:immediate1 ,v)))) ; addl $<v>,0x<n>(%ebp)
(define (i386:accu-mem-add v)
`(("add____$i8,0x8(%eax)" (#:immediate1 ,v)))) ; addl $<v>,(%eax)
(define (i386:value->label label v)
(or v (error "invalid value: value->label: " v))
`(("mov____$i32,0x32" (#:address ,label) ; movl $<v>,(<n>)
(#:immediate ,v))))
(define (i386:value->local n v)
(or n (error "invalid value: value->local: " n))
`(("mov____$i32,0x8(%ebp)" (#:immediate1 ,(- 0 (* 4 n))) ; movl $<v>,0x<n>(%ebp)
(#:immediate ,v))))
(define (i386:local-test n v)
(or n (error "invalid value: local-test: " n))
`(("cmp____$i8,0x8(%ebp)" (#:immediate1 ,(- 0 (* 4 n))) (#:immediate1 ,v)))) ; cmpl $<v>,0x<n>(%ebp)
(define (i386:call-label label n)
`((call32 (#:offset ,label))
("add____$i8,%esp" (#:immediate1 ,(* n 4)))))
(define (i386:call-accu n)
`(,@(i386:push-accu)
,@(i386:pop-accu)
("call___*%eax") ; call *%eax
("add____$i8,%esp" (#:immediate1 ,(* n 4))))) ; add $00,%esp
(define (i386:accu-not)
'(("sete___%al") ; sete %al
("movzbl_%al,%eax"))) ; movzbl %al,%eax
(define (i386:xor-accu v)
(or v (error "invalid value: i386:xor-accu: n: " v))
`(("xor___$i32,%eax" (#:immediate ,v)))) ;xor $0xff,%eax
(define (i386:xor-zf)
'(("lahf") ; lahf
("xor____$i8,%ah" (#:immediate1 #x40)) ; xor $0x40,%ah
("sahf"))) ; sahf
(define (i386:accu-cmp-value v)
`(("cmp____$i8,%eax" (#:immediate1 ,v)))) ; cmp $<v>,%eax
(define (i386:accu-test)
'(("test___%eax,%eax"))) ; test %eax,%eax
(define (i386:jump label)
`(("jmp32 " (#:offset ,label))))
(define (i386:jump-z label)
`(("je32 " (#:offset ,label)))) ; jz . + <n>
(define (i386:jump-byte-z label)
`(("test___%al,%al") ; test %al,%al
("jne8 " (#:offset1 ,label)))) ; jne <n>
;; signed
(define (i386:jump-g label)
`(("jg32 " (#:offset ,label)))) ; jg/jnle <n>
;; signed
(define (i386:jump-ge label)
`(("jge32 " (#:offset ,label)))) ; jge/jnl <n>
(define (i386:jump-nz label)
`(("jne32 " (#:offset ,label)))) ; jnz . + <n>
(define (i386:byte-test-base)
'(("cmp____%al,%dl"))) ; cmp %al,%dl
(define (i386:test-base)
(("cmp____%edx,%eax"))) ; cmp %edx,%eax
(define (i386:byte-sub-base)
'(("sub____%dl,%al"))) ; sub %dl,%al
(define (i386:byte-base-sub)
`(("sub____%al,%dl"))) ; sub %al,%dl
(define (i386:sub-base)
`(("sub____%edx,%eax"))) ; sub %edx,%eax
(define (i386:base-sub)
`(("sub____%eax,%edx"))) ; sub %eax,%edx
(define (i386:nz->accu)
'(("setne__%al") ; setne %al
("movzbl_%al,%eax"))) ; movzbl %al,%eax
(define (i386:z->accu)
'(("sete___%al") ; sete %al
("movzbl_%al,%eax"))) ; movzbl %al,%eax
(define (i386:accu<->stack)
'(("xchg___%eax,(%esp)"))) ; xchg %eax,(%esp)