mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-05 17:47:58 +02:00
239 lines
7.3 KiB
NASM
239 lines
7.3 KiB
NASM
; common startup code for all the memory models
|
|
|
|
%ifdef __TINY__
|
|
%fatal "The tiny memory model is not supported by Windows."
|
|
%elifdef __SMALL__
|
|
%define __NEAR_CODE__
|
|
%define __NEAR_DATA__
|
|
%elifdef __MEDIUM__
|
|
%define __FAR_CODE__
|
|
%define __NEAR_DATA__
|
|
%elifdef __COMPACT__
|
|
%define __NEAR_CODE__
|
|
%define __FAR_DATA__
|
|
%elifdef __LARGE__
|
|
%define __FAR_CODE__
|
|
%define __FAR_DATA__
|
|
%elifdef __HUGE__
|
|
%define __FAR_CODE__
|
|
%define __FAR_DATA__
|
|
%else
|
|
%fatal "Memory model not defined."
|
|
%endif
|
|
|
|
%ifdef __FAR_CODE__
|
|
extra_param_offset equ 2
|
|
%else
|
|
extra_param_offset equ 0
|
|
%endif
|
|
|
|
%ifdef __FAR_DATA__
|
|
extra_data_offset equ 2
|
|
%else
|
|
extra_data_offset equ 0
|
|
%endif
|
|
|
|
cpu 8086
|
|
segment _TEXT use16 class=CODE align=1
|
|
|
|
extern PASCALMAIN
|
|
extern __fpc_PrefixSeg
|
|
extern __fpc_CmdLine
|
|
extern __fpc_CmdShow
|
|
extern __fpc_HInstance
|
|
extern __fpc_HPrevInst
|
|
extern __fpc_SelectorInc
|
|
extern ___stack
|
|
|
|
extern InitTask
|
|
import InitTask KERNEL
|
|
extern WaitEvent
|
|
import WaitEvent KERNEL
|
|
extern InitApp
|
|
import InitApp USER
|
|
extern __AHIncr
|
|
import __AHIncr KERNEL
|
|
|
|
..start: ; Win16 applications start with the following
|
|
; values in registers:
|
|
;
|
|
; AX = zero
|
|
; BX = the size, in bytes, of the stack
|
|
; CX = the size, in bytes, of the heap
|
|
; DI = handle, identifying the new application instance
|
|
; SI = handle, identifying the previous application instance
|
|
; BP = zero
|
|
; ES = segment of the Program Segment Prefix (PSP)
|
|
; DS = segment of the automatic data segment for the application
|
|
; SS = DS
|
|
; SP = offset of the first byte of the application stack
|
|
|
|
; call InitTask to initialize the task. Windows expects this to
|
|
; be the first function, called by the application code. On entry,
|
|
; it expects all the startup parameters in registers described above.
|
|
call far InitTask
|
|
; InitTask result:
|
|
; AX = 1-success; 0-error
|
|
test ax, ax
|
|
jz error
|
|
; InitTask result:
|
|
; CX = stack limit, in bytes
|
|
; DI = instance handle for the new task
|
|
; DX = the nCmdShow parameter
|
|
; ES = segment of the Program Segment Prefix (PSP) for the new task
|
|
; ES:BX = the command line
|
|
; SI = instance handle for the previous application instance (if any)
|
|
|
|
mov ax, es
|
|
mov [__fpc_PrefixSeg], ax
|
|
mov [__fpc_CmdLine+2], ax
|
|
mov [__fpc_CmdLine], bx
|
|
mov [__fpc_CmdShow], dx
|
|
mov [__fpc_HInstance], di
|
|
mov [__fpc_HPrevInst], si
|
|
|
|
; the offset of the Win16 kernel function __AHIncr (by definition)
|
|
; gives us the value of SelectorInc. The function __AHIncr is
|
|
; otherwise useless (when called, it increments AH by one :) )
|
|
; The value of SelectorInc is usually 8 in most (all?) win16
|
|
; implementations, but it's good practice not to hardcode it.
|
|
mov word [__fpc_SelectorInc], __AHIncr
|
|
|
|
; call WaitEvent(0) to clear the event that started this task
|
|
; Windows expects this call immediately after InitTask
|
|
xor ax, ax
|
|
push ax
|
|
call far WaitEvent
|
|
|
|
; call InitApp(hInstance) to initialize the queue and support
|
|
; routines for the app. Windows expects this to be the third
|
|
; call in the Win16 startup sequence.
|
|
push word [__fpc_HInstance]
|
|
call far InitApp
|
|
test ax, ax
|
|
jz error
|
|
|
|
%ifdef __FAR_CODE__
|
|
call far PASCALMAIN
|
|
%else
|
|
call PASCALMAIN
|
|
%endif
|
|
|
|
error:
|
|
mov ax, 4cffh
|
|
int 21h
|
|
|
|
|
|
global FPC_MSDOS_CARRY
|
|
FPC_MSDOS_CARRY:
|
|
stc
|
|
global FPC_MSDOS
|
|
FPC_MSDOS:
|
|
mov al, 21h ; not ax, because only the low byte is used
|
|
pop dx
|
|
%ifdef __FAR_CODE__
|
|
pop bx
|
|
%endif
|
|
pop cx
|
|
%ifdef __FAR_DATA__
|
|
pop si
|
|
%endif
|
|
push ax
|
|
%ifdef __FAR_DATA__
|
|
push si
|
|
%endif
|
|
push cx
|
|
%ifdef __FAR_CODE__
|
|
push bx
|
|
%endif
|
|
push dx
|
|
; global FPC_INTR
|
|
;FPC_INTR:
|
|
%ifdef __FAR_CODE__
|
|
inc bp
|
|
%endif
|
|
push bp
|
|
mov bp, sp
|
|
mov al, byte [bp + 6 + extra_param_offset + extra_data_offset]
|
|
; mov byte [cs:int_number], al
|
|
mov si, [bp + 4 + extra_param_offset]
|
|
push ds
|
|
%ifdef __FAR_DATA__
|
|
mov ax, [bp + 6 + extra_param_offset]
|
|
mov ds, ax
|
|
%endif
|
|
mov ax, word [si + 16]
|
|
mov es, ax
|
|
mov ax, word [si + 14] ; ds
|
|
push ax
|
|
mov ax, word [si]
|
|
mov bx, word [si + 2]
|
|
mov cx, word [si + 4]
|
|
mov dx, word [si + 6]
|
|
mov bp, word [si + 8]
|
|
mov di, word [si + 12]
|
|
mov si, word [si + 10]
|
|
|
|
pop ds
|
|
; db 0CDh ; opcode of INT xx
|
|
;int_number:
|
|
; db 255
|
|
int 21h
|
|
|
|
pushf
|
|
push ds
|
|
push si
|
|
push bp
|
|
mov bp, sp
|
|
%ifdef __FAR_DATA__
|
|
mov si, [bp + 16 + extra_param_offset]
|
|
%else
|
|
mov si, word [bp + 8]
|
|
%endif
|
|
mov ds, si
|
|
mov si, word [bp + 14 + extra_param_offset]
|
|
mov word [si], ax
|
|
mov word [si + 2], bx
|
|
mov word [si + 4], cx
|
|
mov word [si + 6], dx
|
|
mov word [si + 12], di
|
|
mov ax, es
|
|
mov word [si + 16], ax
|
|
pop ax
|
|
mov word [si + 8], ax
|
|
pop ax
|
|
mov word [si + 10], ax
|
|
pop ax
|
|
mov word [si + 14], ax
|
|
pop ax
|
|
mov word [si + 18], ax
|
|
|
|
pop ds
|
|
pop bp
|
|
%ifdef __FAR_CODE__
|
|
dec bp
|
|
retf 4 + extra_data_offset
|
|
%else
|
|
ret 4 + extra_data_offset
|
|
%endif
|
|
|
|
|
|
segment _DATA use16 class=DATA align=2
|
|
; the first 16 bytes of the automatic data segment are reserved.
|
|
; they are filled by the InitTask function with these values
|
|
dw 0
|
|
oOldSP: dw 0
|
|
hOldSS: dw 5
|
|
pLocalHeap: dw 0
|
|
pAtomTable: dw 0
|
|
pStackTop: dw 0
|
|
pStackMin: dw 0
|
|
pStackBot: dw 0
|
|
; end of reserved area, filled by InitTask
|
|
|
|
|
|
|
|
segment stack stack class=STACK align=16
|
|
|
|
group DGROUP _DATA stack
|