home *** CD-ROM | disk | FTP | other *** search
- .386p ; Need p to execute "lsl" to determine limit of data segment.
- .287
-
- ; Here define USING_MASM if you are using Microsoft MASM 5.1 to assemble this.
- ; If you use MASM, you must also use "bd -mtop init.obj" to convert
- ; the MASM object to a Phar Lap object, if you wish to use the Phar Lap linker.
- ; USING_MASM equ 1
-
- name init
- ; (assemble this with "386asm init")
- ;**************************************************************************
- ;*** (c) Copyright 1983 - 1990 MetaWare Incorporated. ***
- ;**************************************************************************
- ;*** You have the same rights to the object form of this program as ***
- ;*** you do to the object code of the library. You may not distribute ***
- ;*** this source, even if modified by you. ***
- ;**************************************************************************
- ;*** The source to this module is provided ***
- ;*** for the convenience of MetaWare Pascal and High C users that need ***
- ;*** to tailor their execution environments. ***
- ;*** The casual user should NOT play with the code. ***
- ;*** This code is subject to change without notice in future releases ***
- ;*** of the compilers. ***
- ;**************************************************************************
- ;*** You must preserve the library copyright notice defined in this ***
- ;*** module if your program uses any portion at all of the run-time ***
- ;*** library (including this initializer or any other supplied run- ***
- ;*** time source). The copyright notice is in the definition of ***
- ;*** the initial stack segment. We recommend it be left right there. ***
- ;*** But you can move it to anywhere you want as long it appears in ***
- ;*** any linked program (.exe or ROM-burned program) using the library.***
- ;**************************************************************************
- ;* *
- ;* MetaWare Pascal or High C Runtime Initialization Module *
- ;* for small model, protected mode 386. *
- ;* *
- ;**************************************************************************
- include model ; Memory model.
-
- ; GROWHEAP.
- ; Dynamic heap expansion.
- ; As an option the run-time system will contract the data area back to
- ; a minimum at start-up, and expand it dynamically.
- ; This is principally useful if you wish to allocate memory separately
- ; from the run-time system using the SETBLOCK (4a) command.
-
- ; Phar Lap's DOS|Extender 1.1t or later can grow the heap dynamically.
- ; For enabling Phar Lap DOS|Extender to grow the heap dynamically,
- ; uncomment the next line.
- PHAR_LAP_CAN_GROW_HEAP equ 1
-
- ; AIA's OS/386 2.0.10 or later can grow the heap dynamically.
- ; For older versions, comment out the next line.
- AIA_CAN_GROW_HEAP equ 1
- ; For Lahey-linked programs, we assume expansion can occur, since such
- ; linked programs do not give you all of memory.
-
- ;-----
- ; The following include file is provided by IGC.
- ; GDA.STR is general data area structure for VM/RUN (X-AM).
- ; Upon entry to target program from VMRUN, EDX --> GDA.
- ; GDA is not useful when solely in the Phar-Lap environment.
- ; Use "gda.h" in the inc/ directory to access the GDA from C:
- ; #include "gda.h"
- ; GDA *gdaptr;
- ;-----
- include gda.str
-
- ; The difference between the Pascal and C run-time initialization
- ; is that in C, the argv array must be allocated and computed.
- ; In Pascal argument processing is handled through a separate argument pacakge.
-
- ; Defines that you can set:
- ; 1. HC. Set if this is for the High C library; not set otherwise.
- ; 2. STACK_SIZE. Set this to the size of the stack you want.
- ; 3. no87. Set this if you know you have no 8087 or 287. It will eliminate
- ; the initialization code for the chip.
- ; Also, it will remove the printing of the "no87" environment variable
- ; if you have an 8087/287 and the no87 variable is set to non-blank string.
- ; (Don't confuse the "no87" define in this assembly from the no87
- ; MS-DOS environment variable. Read the programmer's Guide for more info
- ; on the latter.)
- ; Another reason to set this variable is that you know you're never
- ; going to use an 8087/287, even if you have one. It's especially
- ; useful to remove the printing of the no87 environment variable on
- ; programs for which the 8087/287 processor is irrelevant.
- ; 4. DOS. Set this if this initializer is for MS-DOS (default). Unset it
- ; for embedded applications where DOS doesn't exist. If you unset it,
- ; you won't get argc/argv for C, nor the arg package for Pascal.
- ; It doesn't remove all of the DOS-dependent code -- some of it you must
- ; still rewrite for embedded applications (like how to find the top of
- ; memory). (By "unset" we mean just comment out the line setting it!)
- ; Note that unsetting DOS doesn't remove all DOS-dependent code in
- ; the library. For example, the interrupt handler initialization
- ; uses INT 21h, and so does all I/O. Read the Embedded Applications
- ; section of the Programmer's Guide for more information about how
- ; to change those modules (source is generally provided).
- ; 5. IGC_exists -- Set when IGC environment is possible.
- ; Unsetting it comments out code dependent on that environment only.
- ; 6. PL_exists -- Set when PharLap DOS|Extender environment is possible.
- ; Unsetting it comments out code dependent on that environment only.
- ; 7. NOWTK -- Set if either the Weitek 1167 will never be present
- ; -- or if you never care about it.
- ; 8. XOS -- New 32-bit OS, unreleased.
-
- ; XOS = 1
- ifdef XOS
- no87 = 1 ; There can be no x87 processor.
- NOWTK = 1 ; There can be no Weitek processor.
- else
- IGC_exists = 1
- PL_exists = 1
- endif
-
- DOS equ 1 ; Initializer intended for MS-DOS.
- ; no87 equ 1
-
- ; define HC if the initializer is to be for High C.
- HC equ 1
- ; Pascal is assumed otherwise.
-
- ; Now set expression-identifiers so I can say "if this and not that".
- ; E.g., "compute x" defines macro ex to be 1 ifdef x, 0 otherwise.
- compute macro id
- ifdef id
- e&id = not 0
- else
- e&id = 0
- endif
- endm
-
- compute HC ; HC instead of Prof. Pascal.
- compute XOS
- compute PL_exists
- compute DOS
-
- ;Memory Layout:
- ;
- ; High memory +---------------+
- ; | END OF MEMORY |
- ; |---------------|
- ; | top-of-heap |
- ; | ... |
- ; | bottom-of-heap|
- ; _TOP -> |---------------| <- Of size STACK_SIZE, unless there isn't
- ; | stack | <- room, in which case the first heap
- ; | ... | <- allocation will fail.
- ; | end-of-stack |
- ; _BASE -> +---------------+
- ; DATA segments (static variables and named common)
- ; Low memory CODE segments
- ; See the programmer's guide for more information and pictures of
- ; run-time organization with the different memory models.
- ; Stack margin1 is 512 bytes above the true end-of-stack.
- ; Stack margin2 is 256 bytes above the true end-of-stack.
- ; In non-large models, the stack margins go in a reserved area in the data
- ; segment, not in the stack segment. In the large model, since there is
- ; no single data segment, the stack margins go at the tail end of the stack
- ; (at ss:-2 and ss:-4).
- ;
- ; If stack overflow checking is enabled, here is the code that is generated:
- ; For procedures using 256 or less bytes in the stack:
- ; cmp esp,Stack_margin_1
- ; jnb around
- ; int 0
- ; around: ...
- ;
- ; Since Stack_margin_2 is 512 above true e-o-s, such procedures will always
- ; leave at least 256 bytes (512-256) left in the stack.
- ;
- ; For procedures that use more than 256 bytes:
- ; mov eax,esp
- ; sub eax,Stack_margin_2
- ; cmp eax,Amount_to_allocate
- ; jae around
- ; int 0
- ; around: ...
- ;
- ; Since Stack_margin1 is 256 from true end,
- ; such procedures will leave at least 256 bytes in the stack.
- ;
- ; Therefore, stack overflow occurs when less than 256 bytes would be
- ; left AFTER stack allocation.
- ; This permits the run-time environment to do some processing
- ; such as producing a trace or cleaning up.
-
- STACK_SIZE = 8192 ; default size for stack.
-
- ; Margin-big is used for small procedures -- it ensures a bigger margin.
- ; Margin-small is used for large procedures, since we do more accurate
- ; checking for them.
- Stack_margin_big equ 512 ;Free stack bytes before overflow occurs
- Stack_margin_small equ 256
- Stack_reserve equ 4 ;At top, for the above two numbers (large model).
- STDERR equ 2 ;standard error file handle
-
-
- ;The following dummy segment instructs linker to put "code" lowest
- ;Must be made public since the main module also has public code,
- ;and some primitive linkers can't handle segments of the same name
- ;with different privacy attributes. (This does not include Phar Lap's linker.)
- CODE segment dword public 'CODE'
- CODE ends
-
- DATA segment dword public 'DATA'
- pubname stack_limit
- The_stack_margin equ this word
- def stack_limit,dd,0 ; Stack margins.
- dd 0
- DATA ends
-
- ; Use dword alignment for stack segment in the future.
- STACKNAME equ ?STACK
- if eXOS
- STACKNAME equ STACK
- endif
-
- STACKNAME segment dword stack 'STACK' ; of at least 80 bytes.
- ; Copyright message got moved out of here so that the stack wouldn't
- ; take up space in the .exe file.
- start_of_stack equ this byte
- db STACK_SIZE dup (?) ; The default stack of 8K.
- STACKNAME ends ; MS-DOS loader puts info at the tail end of the stack during loading.
-
- ; Line terminator convention.
-
- _MWLTCONV segment common dword 'DATA'
- ; This must be a MetaWare Pascal string: 2 bytes for the length,
- ; then the actual string characters follow.
- ; Even if the string is of length one, leave the length of this
- ; segment at 8 bytes. (leave lt2 present even if not used.)
- ; Line termination convention for input:
- ltconv_in dw 2 ; length is 2 for line terminator.
- lt1i db 13 ; CR
- lt2i db 10 ; LF
- ; Line termination convention for output; may be of any length:
- ltconv_out dw 2 ; length is 2 for line terminator.
- lt1o db 13 ; CR
- lt2o db 10 ; LF
- _MWLTCONV ends
-
- ifdef HC
- _mwinitfrstcall segment public word 'DATA'
- _mwinitfrstcall ends
- _mwinitmustcall segment public word 'DATA'
- _mwinitmustcall ends
- _mwinitlastcall segment public word 'DATA'
- _mwinitlastcall ends
- endif
-
- ; Define input and output descriptors
-
- dseg segment dword 'DATA'
- ; These are for Pascal but must be provided in C if we link in
- ; the C initializer with Pascal routines.
- pubnames <input,output>
- pubnames <es,is_286,envp,8087,387,1167>
- pubnames <argp,arglen,prognamep>
- pubnames <CPU,OS,env>
- pubnames <emc87,heap_expansion_enabled>
- extrn _osmajor:byte,_osminor:byte
- ifdef HC
- pubname argvp
- endif
- ; Pascal file variables Input and Output. They are initialized in Pascal's Finit.p.
- defequ input,dw,0
- defequ output,dw,1
-
- ; Initialize the "host" package that identifies the system we're running on.
- ; See the interface file Host.pf distributed with Professional Pascal or High C
- ; for the enumerated type declaration for the values of CPU and OS.
- defequ CPU,db,8 ;Indicates 386.
- defequ OS,db,0 ;Indicates MSDOS.
-
- _psp equ this byte
- def es,df,0 ;The contents of es prior to invoking program
- ; df is Microsoft's way of saying 48-bit pointer;
- ; Phar Lap uses dp or df.
- escontents equ _psp ; Program segment prefix pointer.
- ifdef STACK_SIZE
- public _top,_base,_psp
- _top dd 0 ; Top of stack (relative to SS).
- _base dd 0 ; Base of stack (relative to DS).
- _heaphi dd 0
- ifdef IGC_exists
- public _gda
- _gda dd 0 ; Address of gda (softguard only)
- endif
- endif
- defequ argp,df,? ;Pointer to command arguments
- ifdef HC
- defequ argvp,df,? ; Address of argv array for C.
- endif
-
- even
- if eXOS
- pubname is_p
- if not eHC
- defequ is_p,db,1 ; Is the RTE Pascal or C? Affects whether
- else
- defequ is_p,db,0 ; low-level interface clears errno.
- endif
- endif
- defequ arglen,DD,? ;Length of command argument string
- defequ envp,df,0 ;Pointer to environment string
- defequ is_286,db,0 ;True if this is a 286.
- _8087 equ this word ; Need word to store control word into.
- def 8087,dw,0 ;Set to true if 8087 is present
- temp dw 0
- _387 equ this word ; Need word to store control word into.
- def 387,dw,0 ;Set to true if 80387 is present.
- _1167 equ this word
- def 1167,dw,0 ; True if 1167 is present.
- _emc87 equ this word
- def emc87,dw,0 ; Set to true if emc87 is present.
- Null_pname db 0 ; Null prog name for < DOS 3.0.
- ; Prognamep is initialized to a 32-bit pointer to a 0-byte in case
- ; we can't obtain the program name.
- defequ prognamep,dd,Null_pname ;Pointer to program name
- prognamep_seg dw 0
- SG_ENV = 1
- PL_ENV = 2
- AI_ENV = 3
- XOS_ENV= 4
- defequ env,db,0 ; Which environment are we in? SG/PL/AI?
- cur_pages dd 0 ; Current # pages allocated: Phar Lap.
- Lahey_format_load_file db 0 ; .plx (Phar-Lap linked) by default.
- CANT_EXPAND = 0
- CAN_EXPAND = 1
- defequ heap_expansion_enabled,db,CAN_EXPAND ; Is heap expandable?
-
- dseg ends
- envptr equ 2CH ;Offset in DOS ctrl block where env address is located
- ;
- if eDOS
- if not eXOS
- ; We can't put _MWEMCUSED1 in the group dcln because of the 132-character line limitation of the assembler.
- DGROUP group DATA,_MWLTCONV,_mwinitfrstcall,_mwinitmustcall,_mwinitlastcall,dseg,_MW87_USED1,_MW387_USED1,_MW1167_USED1,STACKNAME
- else
- ; XOS doesn't want the stack DGROUPed.
- DGROUP group DATA,_MWLTCONV,_mwinitfrstcall,_mwinitmustcall,_mwinitlastcall,dseg,_MW87_USED1,_MW387_USED1,_MW1167_USED1
- endif
- else
- DGROUP group DATA,_MWLTCONV,dseg,STACKNAME
- endif
-
- ?init segment dword 'CODE'
- CGROUP group ?init,CODE
- assume cs:CGROUP
-
- ; Extern procs must be defined within current code segment for
- ; correct relocation bits to be generated.
- extrn _mwfinit:near
- ; Phar lap assembler won't take next line; it plays according to the rules (as opposed to Microsoft's assembler):
- ;extequ finit,near ;Pascal file system initialization.
- extequ cfinit,near ;C file system initialization.
- extequ halt,near ; Halt intrinsic.
- ifdef HC
- extrn main:near ; Main program entry point
- extequ set_up_args,near ; Routine to compute argv pointers.
- else
- extequ main,near ;Main program entry point
- ;extequ init_interrupts,near ; initialize interrupt handling.
- endif
-
- ; Where are the stack margins defined? Top of stack or in data segment?
- Stack_margin_big_place equ dword ptr DGROUP:The_stack_margin
- Stack_margin_small_place equ dword ptr DGROUP:The_stack_margin+Word_size
- ;
- ; DOS|Extender environment discovery code obtained from Phar Lap:
-
- ;**************************************************************************
- ;* Here begins the execution of a Professional Pascal or High C program. *
- ;**************************************************************************
-
- INIT PROC FAR
- publab INIT ; Compiler generates this in upper case.
- genesis:
- assume ds:DGROUP
-
- jmp short Discover_environment
-
- ; We jump to the rest of the initialization and jump back so that
- ; when debugging we can easily see the call to main as the first call.
-
- Init_return:
- ; In C, Argc/Argv values have been pushed on the stack by the time we get here.
- pcall main ;call main program
- ; compiler generates defn of MAIN
- ; in a main program.
- Quit:
- ; In C, return the value returned by main to the system.
- ; In Pascal, return 0. To return a value in Pascal, use Halt(retcode).
- ifndef HC
- sub eax,eax
- endif
- push eax
- pcall halt
- ifdef IGC_exists
- ; Next 2 lines TEMPORARY for IGC only.
- xor eax,eax ; We shouldn't get here.
- int 21h
- endif
- ifndef HC
- ; Supply a dummy version of "call_onexit_fcns" for Pascal.
- ; Cost: 1 byte here & 3 or 5 bytes for the call in term.p.
- ; Benefits: term.p is the same for Pascal and C.
- publab call_onexit_fcns
- return
- endif
- publab restore_interrupts ; For now, don't bother w/^C.
- return
-
- ifdef HC
- db 'High C'
- else
- db 'Professional Pascal'
- endif
- db ' Run-time Library Copyright (C) 1983-1990 MetaWare Incorporated.'
-
- Discover_environment:
- ifdef IGC_exists
- ; IGC: eax = abcdabcd. Also, code segment is privilege level 3
- ; (= 43 hex).
- cmp al,0cdh ; eax = abcdabcd for IGC.
- jne short not_sg
- cmp ah,0abh
- jne short not_sg
- ; Flaw: If we are in non-protected mode and get this far,
- ; the cmp eax will have 16 bits too much constant, and will
- ; cause the initializer to bomb. It is unlikely that ax=abcd
- ; yet eax <> abcdabcd.
- cmp eax,0abcdabcdh ; Now try 386 instruction.
- jne short not_sg
- mov env,SG_ENV
- mov _gda,edx
- jmp short Initialize_everything
- endif
- if eXOS
- mov env,XOS_ENV
- else
- not_sg: mov env,PL_ENV
- endif
-
- ;INIT: Initialization code
- ; - set initial stackpointer, framepointer
- ; - calls FINIT and CFINIT to initialize file support
- ; - call MAIN to invoke user's program
- ; - call FTERM to close all open files
- ;
- ; Unneeded defn of DGROUP, since DS is fixed.
- ;dsgroup dw DGROUP
-
- ; Shorter than mov reg,-1
- getminus1 macro reg
- sub reg,reg
- dec reg
- endm
-
- ifdef HC
- Small_data_HC = 1
- endif
- SETBLOCK equ 4Ah
-
- ; XOS environment start:
- ; Incoming registers:
- ; esi: initial amount of heap provided by loader, at tail end of DGROUP.
- ; ebx: pointer to argument strings.
- ; edi: pointer to program name.
- ; environ:
- ; ax:0:
- ; (db 'var=value',0)*
- ; (db 0)+ ; possibly some 0 padding for expansion later
- ; ax:edi:
- ; db 'progname',0 ; fully-expanded (drive & path)
- ; ax:ebx:
- ; db 'invoke name',0 ; the invocation prog name.
- ; db 'arguments',0 ; 1 or more arguments.
- ; db 0
- ; handle-table:
- ; dd count
- ; (db type, dd handle)*
- ; type = 0 unused; 1 session; 2 file.
-
- Initialize_everything:
- sub ebp,ebp ;Initialize stack frame pointer
- ; Make sure stack is mod 4 in case it's not.
- and esp,0fffffffch ; Drop extra bytes. Oh well.
- assume ds:DGROUP
-
- if eXOS
- mov word ptr envp+Word_size,ax ; Offset is already 0.
- ; mov envp,0 ; This is already 0.
-
- mov word ptr argp+Word_size,ax ; Offset of arguments.
- mov dword ptr argp,ebx ; Will be adjusted to skip prog name later.
-
- mov word ptr prognamep+Word_size,ax
- mov dword ptr prognamep,edi ; Save prog name offset.
-
- mov ax,ds
- lsl eax,eax ; Find total space.
- mov _heaphi,eax ; End of heap.
- sub eax,esi ; Start of heap.
- mov _top,eax
-
- endif
-
- ; For the 386 we own all of memory. Size up memory and inform the
- ; heap manager.
-
- mov Stack_margin_big_place,Stack_margin_big
- mov Stack_margin_small_place,Stack_margin_small
- add Stack_margin_big_place,offset start_of_stack
- add Stack_margin_small_place,offset start_of_stack
- ifdef IGC_exists
- cmp env,SG_ENV
- je short SG_STACK
- endif
- ifdef PL_exists
- mov _base,0 ; Start of stack.
- lea eax,32[esp] ; eax = start of heap + some padding for safety.
- mov _top,eax
- mov ax,ds
- lsl eax,eax ; load segment limit of data segment.
- mov _heaphi,eax ; Top of heap (linear address).
- endif
- ifdef IGC_exists
- jmp short more_init1
-
- SG_STACK:
- ; Initialize stack, IGC environemnt.
- ; This code will work for h (highest) and a (append after load) stk options.
- ; esp already setup by vmrun loader.
- mov eax,esp ;get stack pointer
- mov ecx,[edx].GDA_STKSZ ;get stack size, kbytes
- shl ecx,10 ;convert from k to # of bytes
- sub eax,ecx ;calculate base of stack addr
- mov _base,eax ;stack base
- mov eax,[edx].GDA_HLOD ;get highest load address
- mov _top,eax ;bottom of heap
- mov ecx,[edx].GDA_HMEM ;get available high memory
- shl ecx,10 ;convert from k to # of bytes
- add eax,ecx ;calculate heap top addr
- mov _heaphi,eax ;top of heap
- ; Free memory below 640K for subsequent use by EXEC.
- mov ebx,[edx].GDA_TLOW ; Subtract highest used low address.
- sub ebx,[edx].GDA_PSPA ; Subtract lowest used low address.
- shr ebx,4 ; Convert to paragraphs.
- inc ebx ; Safety?
- mov ah,SETBLOCK ; SETBLOCK to bx paragraphs from psp start.
- int 21h
- test byte ptr [edx].GDA_ENV,GDA_WEITEK
- setne byte ptr _1167
- endif
-
- more_init1:
- ;*******************************************************************************
- ; Remainder of initialization, independent of where stack lies.
- ;*******************************************************************************
-
- ;*******************************************************************************
- ; Deal with 8087/287
- ; Discover whether 8087/287 exists unless no8087 has been set.
- ;*******************************************************************************
-
- ifdef no87
- mov byte ptr _8087,0
- else
- ; Initialize floating point: check for existence of 8087/287.
- ; We have to do this here so that we can avoid printing out the contents
- ; of NO87 if the machine doesn't have an 8087.
- fninit ;initialize 8087 if one exists
- xor eax,eax ;Initialize 8087 flag to zero.
- mov temp,ax
- sub ecx,ecx ; One byte shorter than mov ecx,15.
- mov cl,15
- ; mov ecx,15 ; Set ch := 0 on first try.
- waste1: loop waste1
- fnstcw temp ; Store cntl word
- ; We used to just test for non-zero on 8087 systems; but that
- ; didn't work for 287s. Even if no 287, IBM ATs returned
- ; garbage as the control word.
- mov cl,15
- waste2: loop waste2
- and temp,00f3fh
- cmp temp,0033fh ; Processor status after initialization.
- jne short no_8087
- fnstsw temp
- mov cl,15
- waste3: loop waste3
- test temp,0b8bfh
- jnz short no_8087
- fldcw cs:fp_init_cw_emc ;load control word
- ; EMC 87 will leave on the upper bit in the control word:
- fstcw temp
- test byte ptr temp+1,80h ; EMC part there?
- jz short not_EMC
- mov byte ptr _387,1 ; EMC also looks like a 387.
- ; We load the normal control word in case someone else stores
- ; it and expects the top bit to be off.
- fldcw cs:fp_init_cw ;load normal control word
- mov byte ptr _emc87,1 ;Say that it's present.
- ; Now fall through to the code that will determine it's also a 387 clone.
- not_EMC:
- mov byte ptr _8087,1 ;Set to TRUE unless he requested to ignore the chip.
- fld1
- fldz
- fdiv ; get infinity
- fld st ; Duplicate TOS.
- fchs
- fcompp ; compare negative infinity with infinity.
- fstsw ax
- fwait
- sahf
- je short no_8087 ; 387 says -inf <> +inf. 87/287 says they're equal.
- mov byte ptr _387,1
- no_8087:
- endif
-
- ifndef NOWTK
- ifdef DOS
- ;*******************************************************************************
- ; Deal with Weitek 1167
- ; Pharlap uses fs:; IGC uses ffc0_0000.
- ; AIA with PharLap linker uses fs:
- ; AIA with Lahey linker uses selector F8h we must load fs explicitly.
- ;*******************************************************************************
- ; Early versions of the emc87 will hang if given weitek code.
- cmp byte ptr _emc87,1
- je Skip_all_weitek_processing
- seg_ldctx macro
- ;pop fs:[0c000h]
- ; Until the assembler will allow address mode override, inline code a 1-byte-shorter move:
- db 67h,64h,8fh,06h,00,0c0h
- endm
- seg_stctx macro
- db 67h,64h,0a1h,00h,0c4h ; store context to eax.
- endm
- flat_ldctx macro
- pop ds:[0ffc0c000h]
- endm
- flat_stctx macro
- pop ds:[0ffc0c400h]
- endm
-
- push 03ff0000h ; truncate (1ff = round to nearest).
- push 30000000h ;
- push 0a0000000h ; 1165 accum timer
- push 64000000h ; 1164 accum timer
- push 16000000h ; 1164/1165 flowthrough timer, 16 mhz
- push 98000000h ; 20 mhz part init
- push 56000000h ; 20 mhz part
- push 0b8000000h ; test speed of chip.
-
- ; ldctx 1600_0000 1164/1165 flowthrough timer.
- ; ldctx 6400_0000 1164 accumulate timer.
- ; ldctx a000_0000 1165 accumulate timer.
- ; ldctx 3000_0000 reserved mode bits.
- ; ldctx 01ff_0000 rounding modes/exception mask.
- ifdef IGC_exists
- cmp env,SG_ENV
- je short SG_weitek
- endif
- ifdef PL_exists
- ; Check that fs <> ds. If so, Weitek installed at fs:.
- mov ax,fs
- mov bx,ds
- cmp ax,bx
- je short NW1
- and ax,ax ; If fs = 0 this was linked with Lahey linker.
- sete Lahey_format_load_file
- jne short go_ahead; if this isn't Lahey we are already (fs = weitek)
- mov ax, 0F8h ; test the f8 selector to see if it exists
- lar bx, ax
- jnz short NW1 ; if no then OS386 does not find a Weitek
- test bh, 80h
- jz short NW1 ; if f8 exists but present bit is not set
- ; os386 does not find weitek
- mov fs, ax
- go_ahead:
- mov _1167,1
- ; Until the assembler will allow address mode override, inline code a 1-byte-shorter move:
- seg_ldctx ; load ctx b8_000_000
- seg_stctx ; store context to eax.
- and ah,80h
- jnz short _20MHZ_part
- pop eax ; Delete 20 mhz init stuff.
- pop eax
- seg_ldctx
- jmp short common_1167
- NW1: jmp short No_weitek
- _20MHZ_part:
- seg_ldctx
- seg_ldctx
- pop eax ; Kill the 16 mhz init.
- common_1167:
- seg_ldctx
- seg_ldctx
- seg_ldctx
- seg_ldctx
- jmp short Finish_weitek
- endif
- SG_weitek:
- ifdef IGC_exists
- cmp byte ptr _1167,1
- jne short No_weitek
- flat_ldctx ; for test.
- flat_stctx ; store context to eax.
- and ah,80h
- jnz short _20MHZ_part_flat
- pop eax ; Delete 20 mhz init stuff.
- pop eax
- flat_ldctx
- jmp short common_1167_flat
- _20MHZ_part_flat:
- flat_ldctx
- flat_ldctx
- pop eax ; Kill the 16 mhz init.
- common_1167_flat:
- flat_ldctx
- flat_ldctx
- flat_ldctx
- flat_ldctx
- flat_ldctx
- jmp short Finish_weitek
- endif
- No_weitek:
- add esp,8*4 ; Get rid of the junk.
- Finish_weitek:
- Skip_all_weitek_processing:
- endif
- endif
-
- ifdef DOS
- ;*******************************************************************************
- ; Process environment area and parameter strings.
- ;*******************************************************************************
- Parm_string_offset = 80h ; Offset in PSP containing parm string (len+bytes).
- ifdef IGC_exists
- cld ;All moves are forward
-
- cmp env,PL_ENV
- je short PL_PSP
- ; GDA has pointer to PSP. PSP has env seg, which, shifted left by 4,
- ; yields the 32 bit address of the env.
- mov edi,[edx].GDA_PSPA ; Get flat PSP address.
- mov word ptr argp+Word_size,ds
- mov dword ptr _psp,edi
- mov word ptr _psp+Word_size,ds
- lea eax,Parm_string_offset[edi] ; eax = pso+edi.
- xor ebx,ebx
- mov bl,[eax] ; Get length of parm string.
- mov arglen,ebx
- inc eax
- mov dword ptr argp,eax ; Addr of parm string.
- mov bx,envptr[edi] ; Get segment address of environment pointer.
- shl ebx,4 ; Convert to 32-bit flat address.
- mov dword ptr envp,ebx
- mov word ptr envp+Word_size,ds ; Fill out 48-bit address
- jmp short more_init2
- PL_PSP:
- endif
-
- if ePL_exists or eXOS
- if ePL_exists
- PSPseg equ 24h ; Pointer to DOS's Program segment prefix: Phar Lap.
- ENVseg equ 2ch ; Pointer to DOS's environment string: Phar Lap.
- cmp Lahey_format_load_file,1
- je short ES_points_to_PSP_already
- mov ax,PSPseg
- mov bx,cs
- arpl ax,bx
- mov es,ax ;Load es with psp address.
- ; Load environment segment into cx.
- mov cx,ENVseg
- arpl cx,bx
- jmp short more
- ES_points_to_PSP_already:
- ; Load environment segment into cx.
- mov cx,es:02ch
- mov ax,es
- more:
- mov word ptr _psp+Word_size,ax ; Construct 48-bit psp address.
- mov word ptr escontents+Word_size,ax ;No displacement
- mov word ptr envp+Word_size,cx ; Environment segment.
- xor eax,eax
- mov al,es:Parm_string_offset ;Length of parm string
- mov arglen,eax
- mov esi,Parm_string_offset+1
- endif
- if eXOS
- ; Compute arglen. First skip over the useless invocation name.
- les edi,argp
- getminus1 ecx
- xor eax,eax
- repnz scasb ; Search for 0.
- ; edi now points to the byte afterwards; it must point to the
- ; argument string.
- mov dword ptr argp,edi ; Points to command-line arguments.
- mov esi,edi ; Save for what comes next in HC.
- mov ebx,edi ; Start pointer
- repnz scasb ; Look for terminating 0.
- sub edi,ebx ; arglen; includes the 0.
- dec edi
- mov arglen,edi ; Length of arugment string.
- mov eax,edi ; For what comes next.
- endif
-
- ; In C, the parameter string must be moved to a DS-accessible area
- ; if small-data model.
- ifdef HC
- ; Move the parm string into the stack so that it can be accessed by
- ; small-data programs with only 16-bit pointers.
- add eax,3
- and al,0fch ; Make sure eax is multiple of 4.
- sub esp,eax ; Length of parm string.
- mov edi,esp ; Move the parameter string here.
- mov dword ptr argp,edi ; Save address of args.
- push edx ; Allow byte for parm string overwrite by C arg processor.
- ; but make stack word-aligned for efficiency.
- mov ecx,eax ; parameter length
- push ds ; Save it.
- push es ; source is es:esi
- pop ds
- push es ; Save es.
- push ss
- pop es ; Dest is ss:di.
- ; mov esi,Parm_string_offset+1 ; Set up earlier.
- rep movsb ; es:di := parm string.
- pop es
- pop ds
- else
- ; Large-data or Pascal model; just store the address of the parms.
- if not eXOS
- mov ax,word ptr escontents+Word_size
- mov word ptr argp+Word_size,ax
- mov dword ptr argp,Parm_string_offset+1 ; Addr of parm string.
- endif
- endif
- endif
-
- more_init2:
-
- if not eXOS
- ; In DOS 3.0 and higher, the program name is stored at the end of the
- ; environment variable area, terminated by a 0 byte.
- ; We need to discover DOS version to see if we should get the pname.
- sub eax,eax
- mov ah,30h ; Get DOS version number
- int 21h
- mov word ptr _osmajor,ax ; Moves minor (AH) and major (AL).
- cmp env,SG_ENV
- je short no_change
- shr eax,16
- cmp ax,'DX'
- jne short to_ai ; by default this must be AIA's OS386
- ; Phar Lap.
- ifndef PHAR_LAP_CAN_GROW_HEAP
- jmp short no_change
- else
- ; Now free all of the heap, so that we allocate more only when necessary.
- mov ax,4
- mov es,ax
- mov ebx,es:[5ch] ; Initial size of heap: load image size in bytes.
- ; See Phar Lap TN #21.
- jmp short Free_up
- endif
- to_ai:
- mov env,AI_ENV
- mov ebx, _top ;top of stack in bytes
- ifndef AIA_CAN_GROW_HEAP
- cmp Lahey_format_load_file,1
- jne short no_change
- ; If Lahey format, we must be able to grow.
- endif
- Free_up:
- add ebx,4095 ; Round up to pages.
- shr ebx,12 ; Convert to 4K pages.
- inc ebx ; Add 1 page for initial heap.
- mov cur_pages, ebx
- mov edx, ebx
- shl edx,12 ; Future value for heaphi.
- cmp env,PL_ENV
- je short No_para
- shl ebx, 8 ; Convert pages to paragraphs for AIA.
- cmp Lahey_format_load_file,1
- jne short No_para ; if AI_ENV and PL linker skip to allocation
- ; else must be AI_ENV and Lahey Linker so
- ; we must grow the parent segment first
- call grow_parent_segment
- No_para:
- push ds
- pop es ; Segment to free up.
- mov ah,SETBLOCK ; SETBLOCK to bx paragraphs from psp start.
- int 21h
- jc short no_change ; If couldn't get the extra page, oops!
- mov _heaphi,edx
- no_change:
- endif
-
- doesnt_want_8087 macro
- ; All this fuss just to print the NO87 string!
- ifndef no87
- push eax
- push edi ; We're going to clobber these.
- cmp _8087,0
- je short no_print; No 87 exists on this machine; don't bother to print.
- mov _8087,0 ; Set false.
- add edi,5
- mov esi,edi ; Copy for later.
- mov al,' '
- repe scasb
- dec edi
- cmp byte ptr es:[edi],0 ; Did we get to end of string?
- je short no_print
- mov edi,esi ; Now print the message, one character at a time.
- again: mov dl,es:[edi]
- and dl,dl
- je short end_of_string
- mov ah,6 ; Direct Console I/O.
- int 21h ; Print character.
- inc edi
- jmp again
- end_of_string:
- mov dl,0dh ; \r\n.
- mov ah,6
- int 21h ; Print character.
- mov dl,0ah
- mov ah,6
- int 21h ; Print character.
- no_print:
- pop edi
- pop eax
- endif ; no87
- endm
-
- Find_prog_name:
- ; -- Format of DOS environment: VVV 3.x only VVV
- ; -- t1 nul t2 nul t3 nul ... tn nul nul x x program-name nul
- ; Go to end of environment string to get program name for DOS 3.0.
- ; While we're doing so, see if he said "NO87=" something, in which case,
- ; mimicking Microsoft's emulator, we print the string (unless it's
- ; nothing but blanks), and disable use
- ; of the 80287 if the combination emulation/80287 library is linked in.
- les edi,envp ; Pointer to environment area.
- cmp byte ptr es:[edi],0 ; No environment?
- je no_environment_at_all
- xor eax,eax ; search for 0 byte.
- Scan_again:
- cmp dword ptr es:[edi],'78ON' ; NO87
- jne short not1
- cmp byte ptr es:4[edi],'=' ; =
- jne short not1
- doesnt_want_8087 ; Macro back-substituted here.
- not1: getminus1 ecx ; Search lotsa bytes.
- repnz scasb ; Search for 0.
- ; We MUST have found the 0 byte; we're positioned at the byte after.
- cmp byte ptr es:[edi],0 ; Two 0 bytes in a row?
- jne Scan_again ; Nope, keep going.
- if not eXOS
- ; Now we've found the environment area end. +3 bytes later is the prog name.
- add edi,3 ; Move to program name.
- cmp _osmajor,3 ; Program name supplied by OS?
- jb short NO_PNAME_AVAIL
- cmp env,SG_ENV
- jne short get_pname
- cmp env,AI_ENV
- je short get_pname
- ; IGC: pname is addressable.
- mov dword ptr prognamep,edi
- mov word ptr prognamep+Word_size,ds
- jmp short _prog_name
-
- NO_PNAME_AVAIL:
- ; No program name. Supply the null string.
- ifdef HC
- ; Allocate the null byte on the stack right after the parms.
- xor edx,edx
- push edx ; Null byte(s).
- mov dword ptr prognamep,esp ; Pointer to the program name.
- endif
- jmp short _prog_name
- endif ; not XOS
-
- get_pname:
- if ePL_exists or eXOS
- PL_PN:
- if eXOS
- les edi,fword ptr prognamep ; or pword ptr prognamep.
- endif
- ; In small-data C, the program name must be moved into the DS group.
- ifdef Small_data_HC ; Move the program name to the stack.
- xor eax,eax
- ; Find length of program name.
- getminus1 ecx
- mov ebx,edi ; Save starting address of name.
- repnz scasb
- sub edi,ebx ; Length of name (including 0 trailer).
- lea eax,3[edi] ; Add some space on stack...
- and eax,0fffch ; Ensure mod 4 for nice value for SP.
- sub esp,eax ; Allocate space for name.
- mov dword ptr prognamep,esp ; Where the name will be put.
- mov ecx,edi ; Length of name
- mov esi,ebx ; Name is stored here.
- mov edi,esp ; Copy to here.
- push ds
- mov ds,word ptr envp+Word_size
- push ss
- pop es
- rep movsb
- pop ds
- else
- ; Non-small data case: just record the address.
- mov dword ptr prognamep,edi
- mov word ptr prognamep+Word_size,es
- endif
- endif
-
- no_environment_at_all:
- _prog_name:
-
- ifdef HC
- ; Now allocate the space for the argv pointers. One for the program name
- ; and one for each argument. Although we don't know how many arguments there
- ; are, there can be at most 1 for every two characters of the environment
- ; string.
- mov eax,arglen
- inc eax
- shr eax,1 ; Max arg ptrs for parameters
- inc eax ; Count the program name.
- inc eax ; ANSI requires argv[argc] = null pointer.
- shl eax,2 ; Multiply by pointer size
- sub esp,eax ; Now allocate it.
- mov dword ptr argvp,esp ; sp is here.
- endif ; HC
-
- endif ; DOS
-
- ;call file and user initialization, call main program
-
- assume ds:DGROUP
- push ds
- pop es
- ; ss is already = ds.
- ; Since this is in Pascal, we must initialize ds first!
- ; call init_interrupts
- ; Phar lap asssembler won't take:
- ; pcall finit ;initialize Pascal file system.
-
- mov ebx,offset ds:_mwinitfrstcall
- mov ecx,offset ds:_mwinitlastcall
- sub ecx,ebx
- mustcall: or ecx,ecx
- jz mustdone
- mov edi,[ebx]
- add ebx,4
- sub ecx,4
- ifndef Small_code
- mov esi,[ebx]
- add ebx,2
- sub ecx,2
- endif
- or edi,edi
- jz mustcall
- push ebx
- push ecx
- ifdef Small_code
- call edi
- else
- push edi
- push esi
- mov ebx,sp
- call dword ptr [ebx]
- pop ecx
- pop ecx
- endif
- pop ecx
- pop ebx
- jmp mustcall
-
- mustdone:
-
- pcall _mwfinit ;initialize Pascal file system.
- pcall cfinit ;initialize C file system.
- ifdef HC
- ; In preparation for calling main, push addr of argv.
- ifndef Small_data
- push word ptr Argvp+2 ; push segment
- endif
- push dword ptr argvp ; Push offset.
- sub eax,eax ; In case he supplies dummy routine: argc = 0.
- pcall set_up_args ; Find argv values by scanning argument string.
- push eax ; Push computed ArgC.
- endif
- ifdef DOS
- ; Now check if he used the 1167, but it doesn't exist.
- _MW1167_USED1 segment common byte 'DATA'
- magic6 dw 1 dup(?) ; Not initialized.
- offoops6 dd 1 dup(?) ; Not initialized.
- oopsptr6 dd 1 dup(?) ; Not initialized.
- _MW1167_USED1 ends
- cmp byte ptr _1167,1
- je short OK3 ; If 8087 there, no further checking needed.
- cmp magic6,0abcdh
- jne short OK3
- mov eax,oopsptr6
- cmp eax,offoops6
- jne short OK3
- mov edx,oopsptr6
- jmp short more_message
- OK3:
- ; Now check if he used the Cyrix EMC 87, but it doesn't exist.
- _MWEMC_USED1 segment common byte 'DATA'
- magic7 dw 1 dup(?) ; Not initialized.
- offoops7 dd 1 dup(?) ; Not initialized.
- oopsptr7 dd 1 dup(?) ; Not initialized.
- _MWEMC_USED1 ends
- cmp byte ptr _emc87,1
- je short OK4 ; If 8087 there, no further checking needed.
- cmp DGROUP:magic7,0abcdh
- jne short OK4
- mov eax,DGROUP:oopsptr7
- cmp eax,DGROUP:offoops7
- jne short OK4
- mov edx,DGROUP:oopsptr7
- jmp short more_message
- OK4:
- ; Now check if he used the 8087, but it doesn't exist.
- ; Here is how we determine if he dragged in fltused from the library:
- ; magic will have a "magic" value, and offoops will have the offset of
- ; the "oops" message. If _mw87_used is not hauled in, magic and offoops
- ; will be 0 when using all linkers under MS-DOS; on the Intel linkers
- ; they wil be garbage and WE HOPE THAT the fields won't accidentally
- ; look correct. This is not foolproof, therefore, with linkers that don't
- ; zero out unitialized memory, but it is much
- ; cheaper than checking in the RTL for the 8087 presence for each 8087
- ; operator invoked. I WISH OMF provided a "segment length"
- ; fixup; then this could be made foolproof.
- _MW87_USED1 segment common byte 'DATA'
- magic dw 1 dup(?) ; Not initialized.
- offoops dd 1 dup(?) ; Not initialized.
- oopsptr dd 1 dup(?) ; Not initialized.
- _MW87_USED1 ends
- cmp byte ptr _8087,1
- je short OK ; If 8087 there, no further checking needed.
- cmp magic,0abcdh
- jne short OK
- mov eax,oopsptr
- cmp eax,offoops
- jne short OK
- mov edx,oopsptr
- more_message:
- mov ah,9
- int 21h
- jmp Quit
- OK: ; Did he require 387, and is it here?
- _MW387_USED1 segment common byte 'DATA'
- magic3 dw 1 dup(?) ; Not initialized.
- _MW387_USED1 ends
- cmp byte ptr _387,1
- je short OK2
- cmp magic3,0abcdh
- jne short OK2
- ; He used it, but it's not present.
- mov edx,cs:oops3ptr
- mov ah,9
- int 21h
- mov edx,oopsptr
- add edx,10 ; Skip past "8087/80287".
- jmp more_message
- _387msg db '80387','$'
- oops3ptr dd offset _387msg
- OK2:
-
- endif
- jmp Init_return
- fp_init_cw dw 03FFH ; For initializing 8087/287.
- fp_init_cw_emc dw 83FFH ; For initializing EMC 87.
- ; The 8000 is for testing presence of EMC 87 part.
- assume es:nothing
-
- INIT endp
-
- ; Next three routines are used by sysalloc and sysfree.
-
- ;**************************************************************************
- ; function Heaplo(): Unsigned; ; Returns bottom of heap space.
- ;**************************************************************************
- ; This function returns the starting address of the heap.
- ; The heap is just above the stack.
-
- db 0
- heaplo proc far
- publab heaplo
- ; return ss:_top; paragraph if non-small-data model.
- mov eax,_top
- add eax,16
- return
- heaplo endp
-
- ;**************************************************************************
- ; function Heaphi(): Unsigned; ; Returns top of heap space.
- ;**************************************************************************
- ; This returns the estimated top of the area that can be used
- ; for the heap.
-
- db 0
- heaphi proc far
- publab heaphi
- mov eax,_heaphi
- return
- heaphi endp
-
- if AIA_CAN_GROW_HEAP
- grow_parent_segment proc near
- push ebx ; save regs that get altered
- push edi
- push es
-
- push ebx ; save paras - we need BX for OS386 call
- push edx ; this int 21 trashes edx
- mov ax, 0ED00h ; get info on segment which is to be grown
- mov bx, ds
- int 21h
- pop edx ; restore edx
- pop ebx ; DI now contains parent segment for DGROUP
-
- mov es, di ; now shrink this segment to paras in EBX
- mov ah, SETBLOCK
- int 21h
-
- pop es
- pop edi ; restore regs
- pop ebx
- ret
- grow_parent_segment endp
- endif
-
- ; The heap manager calls this routine to expand the heap when it
- ; detects a heap overflow. The expansion expands allocates more memory
- ; starting at _heaphi. Record the new top-of-heap in _heaphi.
- ; Currently this is implemented only for Phar Lap's DOS|Extender and
- ; AIA's OS386.
- expand_heap proc far
- publab expand_heap
- if not eXOS
- push ebx
- ; Has the user shut off heap expansion?
- cmp heap_expansion_enabled,CANT_EXPAND
- je short Cant_grow
- cmp env,PL_ENV
- ifndef PHAR_LAP_CAN_GROW_HEAP
- je short Cant_grow ; Must have release >= 1.1t.
- else
- je short Can_grow
- endif
- ifndef AIA_CAN_GROW_HEAP
- cmp Lahey_format_load_file,1
- jne short Cant_grow
- ; If Lahey format, we must be able to grow.
- else
- cmp env,AI_ENV
- jne short Cant_grow
- endif
- Can_grow:
- mov ebx,8[esp] ; Request for more bytes.
- add ebx,4095 ; Round to pages.
- shr ebx,12
- add ebx,cur_pages
- inc ebx ; Always have 4K of extra room.
- push ebx ; Save it.
- cmp env,AI_ENV
- jne short pages
- shl ebx, 8 ; convert pages to paragraphs for AI.
- cmp Lahey_format_load_file,1
- jne short pages ; if AI_ENV and PL linker skip to allocation
- ; else must be AI_ENV and Lahey Linker so
- ; we must grow the parent segment first
- call grow_parent_segment
- pages:
- mov ah,SETBLOCK
- int 21h
- pop eax ; Amount requested.
- jc short Cant_grow
- mov cur_pages,eax
- shl eax,12
- mov _heaphi,eax
- ; mov _heaphi,new top address of heap.
- Cant_grow:
- pop ebx
- else
- mov eax,_heaphi ; End of data segment currently.
- add eax,4[esp] ; He wants this much more heap added.
- inc eax ; New size requested.
- add eax,4192 ; Always have 4K extra slop.
- add eax,8192-1
- and ax,not (8192-1)
- ; Round up to 8K segments.
- push eax ; Save the new size.
- sub eax,eax
- mov ax,ds
- push eax
- push 0
- extrn CPReallocSeg:near
- pcall CPReallocSeg
- xor eax,eax
- jnz short Cant_grow
- mov ax,ds
- lsl eax,eax
- mov _heaphi,eax ; Save new top.
- Cant_grow:
- endif
- return 4
- expand_heap endp
-
- ;**************************************************************************
- ; procedure set_stack_limits(small,large:Cardinal);
- ;**************************************************************************
- ; Set the two limits.
- ; This is called by the heap manager when the heap begins to creep
- ; into the stack, or when the heap has left the stack area.
- ; Basically, when the heap has used the lower portion of the stack,
- ; the stack margin variables are set to reflect a higher bottom-of-stack
- ; location, so that stack overflow will occur when the stack is within
- ; 256 bytes of the heap.
- ; If the stack precedes the heap, the heap never creeps into the
- ; stack and this procedure will never be called.
-
- Set_stack_limits proc far
- publab set_stack_limits
- return 8
- Set_stack_limits endp
- ;
- ;**************************************************************************
- ; function ss: Cardinal; {Returns paragraph address of stack segment
- ;**************************************************************************
- ;
- ssx proc far
- publab ss
- mov ax,ss
- return
- ssx endp
-
- ;**************************************************************************
- ; function Getds: Cardinal; -- Returns ds register.
- ;**************************************************************************
- ; This function may actually no longer be needed.
-
- ifdef Small_data
- getds proc far
- publab getds ; return ds register.
- mov ax,ds
- return
- getds endp
- endif
-
- ?init ends
- end CGROUP:genesis
-