SECTION .text
;---------------------------------------------------------------------
; Multiple push/pop
;	push eax,ebx,ecx...
;	pop eax,ebx,ecx...

%macro push 1-*.nolist
%rep %0
	push dword %1
%rotate 1
%endrep
%endmacro

%macro pop 1-*.nolist
%rep %0
%rotate -1
	pop dword %1
%endrep
%endmacro
%macro dup 0
        sub esi,byte 4
        mov [esi],eax
%endmacro
%macro drop 0
        lodsd
%endmacro
%macro variable 2
       call dovar
       %1 dd %2
%endmacro
%macro swap 0
       xchg eax,[esi]
%endmacro
%macro nip 0
       add esi,byte 4
%endmacro
%macro rot 0
%endmacro

%macro embed 1
   upsh %%e1
   upsh [%%e2]
   call eval	
   jmp short %%e3
%%e1 db %1
%%e2 dd $-%%e1
%%e3
%endmacro


%macro next 0
       ret
%endmacro

%macro upsh 1
        dup
        mov eax,%1
%endmacro
%macro upop 1
        mov %1,eax
        drop
%endmacro

%macro code 1
section .text
global $%1
$%1:
%endmacro

; =====================================================================
	global _start
_start:
	mov eax, 07dh              ;sys mprotect (pinched from IsForth :-)
	mov ebx, 08048000h
	mov ecx, 00100000h
	mov edx, 7
	int 080h                   ;make the entire program space rwx

	lea esi, [esp-0x200]	;Initialize data stack
        call main
	call bye		; Make sure this exits
; =====================================================================
; ======================================================================
; SEDForth for Linux, Release 0.0.1
; Primitives (for inlining!)
; ======================================================================

code abs
 mov ebx,eax                ;set ebx = sign of n1
 sar ebx,byte 31            ;propogate sign bit if n1 throughout ebx
 xor eax,ebx                ;will invert n1 if n1 was negative
 sub eax,ebx                ;will subtract -1 if n1 was negative
next

code minus
     sub [esi],eax			; -
     drop
next


code mod
        upop ebx			; MOD
        xor edx,edx
        idiv ebx
        mov eax,edx
next

code plus
  add eax,[esi]			; +
  add esi,byte 4
next

code divide
        upop ebx			; /
        xor edx,edx
        idiv ebx
next

code multiply
     mul dword [esi]			; *
     add esi,byte 4
next

code forth_and
	and eax,[esi]
            add esi,byte 4
next

code equals
 sub eax,[esi]                ;subtract n1 from n2
 sub eax,byte 1             ;see if result was 0
 sbb eax,eax
 add esi,byte 4
next

code lessthan
 cmp eax,[esi]                ;compare them
 jl logic_less_1
 xor eax,eax                ;return result
 add esi, byte 4
next
logic_less_1:
 mov eax,dword -1           ;or this one :)
 add esi, byte 4
next

code max
 cmp eax, [esi]               ;which is larger
 jl logic_max_1              
 mov [esi], eax			;n2 is larger
logic_max_1:			;n1 is larger
 mov eax, [esi]
 add esi, byte 4
next

code min
 cmp eax, [esi]               ;which is smaller
 jg logic_min_1              
 mov [esi], eax			;n2 is smaller
logic_min_1:			;n1 is smaller
 mov eax, [esi]
 add esi, byte 4
next

code not
            not eax
next

code forth_or
	      or eax,[esi]
            add esi,byte 4
next

code forth_xor
	xor eax,[esi]
            add esi,byte 4
ret

section .data
call dovar
base dd 10

code print
	push edx
	push edi
	mov edi,esi	;edi = buffer (in stack space)
	sub edi,4
	or eax,eax	;Negative?
	jns .1
	neg eax
	upsh '-'
	call emit
.1			;Convert
	xor edx,edx
	div dword [base]
	add dl,'0'
	cmp dl,'9'
	jbe .2
	add dl,7+32
.2	dec edi
	mov [edi],dl
	or eax,eax
	jnz .1
	mov eax,edi	;Print
	upsh esi
	sub eax,edi	;# of digits
	call type
	pop edi
	pop edx
	upsh ' '	; And add one space after
	call emit	; the number
next

code type
	push ebx
	push ecx
	upop ecx
	upop ebx
	or ecx,ecx	; Is the count zero?
	jz .done	; If so, we can exit
	.1 	push ecx	; store the count
	dup		; Duplicate it
	xor eax,eax 	; Filter out junk bits
	mov al,[ebx]	; Obtain the byte to show
	inc ebx		; increment to the next byte
	call emit	; Show the character
	pop ecx		; Restore the count
	loop .1		; Loop, decrementing the count
.done	pop ecx
	pop ebx
next


code cstore
	upop edx
	mov [edx], al
	drop
next
code cfetch
	upop edx
	dup
	xor eax,eax
	mov al, [edx]
next
code store
	upop edx
	mov [edx],eax
	drop
next
code callcomma
	mov ebx, eax
	drop
	call ebx
next
code spfetch
	upsh esi
next
code fetch
	mov eax,[eax]
next

section .data
call dovar
s_dest dd 0

code s
	upop [s_dest]
	mov [tp],dword tib
.0	call key
	cmp al,10
	je .done
	xchg edi,[tp]
	stosb
	xchg [tp],edi
	call emit
	jmp short .0
.done	push ecx	;move string to a safer place...
	push edi
	mov edi,[s_dest]
	mov eax,edi ;push addr
	dup
	push esi
	mov ecx,[tp]
	mov esi,tib
	sub ecx,esi
	mov eax,ecx	;push length
	rep movsb
	pop esi
	pop edi
	pop ecx
	call cr
next

; ( source dest count -- )
code cmove
	mov ecx,eax
	drop
	mov edi,eax
	drop
	push esi
	mov esi,eax
.1	mov edx, [esi] 
	mov [edi], edx
	inc edi
	inc esi
	loop .1
	pop esi
	drop
next



; =======================================================================
; Linux and Driver Specific Words
; =======================================================================
code bye
	sub ebx,ebx	;Return exit status 0
	mov eax,ebx
	inc eax		;1 = sys_exit
	int 80h
code cr
	upsh 10
	call emit
	ret
code emit
	push ebx,ecx,edx
	mov ebx, 1	;stdout
	mov edx, ebx	;count
	lea ecx, [esp-4]
	mov [ecx], eax
	mov eax, 4	;sys_write
	int 80h
	pop ebx,ecx,edx
	drop
	ret
code key
	dup
	push ebx,ecx,edx
	sub ebx,ebx	;0 = stdin
	mov edx, 1	;count
	lea ecx, [esp-4]
	mov eax, 3	;sys_read
	int 80h
	mov eax, [ecx]
	pop ebx,ecx,edx
	ret
; =======================================================================
code hex
  upsh 16
  upsh base
  call store
ret
code decimal
  upsh 10
  upsh base
  call store
ret
code octal
  upsh 8
  upsh base
  call store
ret
code binary
  upsh 2
  upsh base
  call store
ret
code here
  upsh [h]
ret
code pick
  upsh 4
  call multiply
  call spfetch
  call plus
  call fetch
ret
code neg
  upsh -1
  call multiply
ret
code dividemod
  call over
  call over
  call divide
  rot
  rot
  call mod
ret
code multiplydivide
  call multiply
  call divide
ret
code multiplydividemod
  call multiply
  call dividemod
ret
code lessthangreaterthan
  call equals
  call $not
ret
code greaterthan
  swap
  call lessthan
ret
code off
  call false
  swap
  call store
ret
code on
  call true
  swap
  call store
ret
code plusstore
  swap
  call over
  call fetch
  call plus
  swap
  call store
ret
code plusplus
  upsh 1
  call plusstore
ret
code minusminus
  upsh -1
  call plusstore
ret
code align
  upsh 0
  call here
  upsh 4
  call mod
  call xcomma
ret
code allot
  call xcomma
ret
code cellplus
  upsh 4
  call plus
ret
code cells
  upsh 4
  call multiply
ret
code charplus
  upsh 1
  call plus
ret
code chars
  upsh 1
  call multiply
ret
code false
  upsh 0
ret
code true
  upsh -1
ret
code dovar
	dup
	pop eax
	ret
;---------------------------------------------------------------
; n SIZE x,

code xcomma
        upop ecx
	mov edx,[h]
	mov [edx],eax
	drop
	add edx,ecx
	mov [h],edx
	ret

code minusrot
  rot
  rot
next
code over
  call spfetch
  upsh 4
  call plus
  call fetch
next
code nip
  swap
  drop
ret
code tuck
  swap
  call over
ret
code twodup
  call over
  call over
ret
code twodrop
  drop
  drop
ret


section .bss
tib resb 200h
h0 resb 80000h
section .text


tp dd tib
tin dd 0

code buffer
  upsh tib
ret

h call dovar
dd h0
