; ( Retro Project )
; ( Development Macros, NASM Edition )
; ( These are mainly intended for use with Forth, but )
; ( other languages or tools may depend on them. )
; ( FILE: /include/macros )
; ( --------------------------------------------------- )


; ( --------------------------------------------------- )
; ( Register Managment )

; ( 32-bit -> 16-bit Registers )
%ifdef M8088
  %define eax ax
  %define ebx bx
  %define ecx cx
  %define edx dx
  %define esi si
  %define edi di
  %define esp sp
%endif

; ( Forth Registers -> x86 Registers )
%define TOS eax  ; ( Top of Stack )
%define PSP esi  ; ( Program Stack Pointer )
%define RSP esp  ; ( Return Stack Pointer )
%define W   edi  ; ( Working Register )
%define UP  ---  ; ( User Pointer, unused )
%define C   ecx  ; ( Count, non-standard )
; ( --------------------------------------------------- )




; ( --------------------------------------------------- )
; ( Easier handling of the  hardware stack, Courtesy of )
; ( Tom Novelli                                         )
; (   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


; ( --------------------------------------------------- )
; ( Forth primitives for use in the assembly core of    )
; ( Retro Native Forth. These are inlined               )
%macro dup 0
        sub PSP,byte 4
        mov [PSP],TOS
%endmacro
%macro drop 0
        lodsd
%endmacro
%macro swap 0
       xchg eax,[esi]
%endmacro
%macro nip 0
       add esi,byte 4
%endmacro


; ( --------------------------------------------------- )
; ( Easier handling of the Forth stack                  )
%macro upsh 1
        dup
        mov eax,%1
%endmacro
%macro upop 1
        mov %1,eax
        drop
%endmacro


; ( --------------------------------------------------- )
; ( Dictionary Macros (based on IsForth's)
; ( Courtesy of Tom Novelli )

%xdefine vlink 0            ;link to previous word in vocabulary
%xdefine forth_link 0       ;link to previous word in forth vocab
%xdefine macro_link 0       ;link to previous word in compiler vocab
%xdefine voc 0              ;currently linking to forth vocabulary

%macro header 2.nolist
%%link:
 dd vlink                   ;link to previous word in vocabulary
 dd %2                      ;pointer to cfa (in .text section)
 db (%%name-$-1)            ;name length + flags
 db %1                      ;name
%%name:
%xdefine vlink %%link
__SECT__
 forth                      ;Switch back to 'forth' vocab!!!
%endmacro

; Usage: code 'forth-name', asm-name
%macro code 2.nolist
 header %1,%2               ;create header in head space
%2:                         ;make label for new coded definition
%endmacro


; Usage: var 'name',name,value
%macro var 3.nolist
 code %1, ?%2
 call dovar
 %2 dd %3
%endmacro

; Usage: const 'name',name,value
%macro const 3.nolist
 code %1, ?%2
 call doconstant
 %2 dd %3
%endmacro

%macro save_link 0.nolist
 %if(voc = 0)               ;were we linking on the forth vocabulary ?
  %xdefine forth_link vlink ;yes - set new end of forth vocab
 %elif(voc = 1)             ;were we linking on the macro vocabulary ?
  %xdefine macro_link vlink ;yes - set new end of macro vocab
 %endif
%endmacro

; Link all new definitions to the forth vocabulary
%macro forth 0.nolist
 save_link                  ;save link address of previous vocabulary
 %xdefine vlink forth_link  ;start linking on forth vocabulary
 %define voc 0
%endmacro

; Link all new definitions to the compiler vocabulary
%macro macro 0.nolist
 save_link                  ;save link address of previous vocabulary
 %xdefine vlink macro_link  ;start linking on 'macro' vocabulary
 %define voc 1
%endmacro

; ( --------------------------------------------------- )
; ( Small macros used to make programming easier        )
; ( Are these needed? Try to eliminate them if possible )
%macro variable 2
       call dovar
       %1 dd %2
%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 $at 2	;$at x,y
	mov dword [xy], %2+(%1<<16)
%endmacro

%macro $color 1	;$color 14
	mov [fore],byte %1
%endmacro

%macro case 2
cmp eax, %1
jz .%2
%endmacro
