DataMuseum.dk

Presents historical artifacts from the history of:

CP/M

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about CP/M

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦6a4561b89⟧ TextFile

    Length: 52480 (0xcd00)
    Types: TextFile
    Names: »STARTUP.A86«

Derivation

└─⟦93c4d868c⟧ Bits:30005869 SW1609 Digital Research C v. 1.11 - May 84
    └─ ⟦this⟧ »STARTUP.A86« 
└─⟦b85731168⟧ Bits:30002664 Digital Research C - CCP/M - May 84
    └─ ⟦this⟧ »STARTUP.A86« 

TextFile

	Name		'STARTUP'
	Title		'STARTUP for DRC V1.11'
	Pagesize	75
;
; This startup file is actually several files edited together:
; clear.a86, minit.a86, minitrel.a86, minitsta.a86, minithea.a86, minitcmd.a86,
; miniterr.a86, minitos.a86.  The include statements and public/extrn
; statements that connect the separate files have been commented out.
; Each such comment has the initials ACF on it.
;
; Notes to the user.
;
; Only the most sophisticated user, with a thorough knowledge of the 8086,
; CP/M, RASM86, LINK86, the .CMD file format, and the C calling conventions,
; should attempt to write a startup routine.  These notes will explain how
; this one was written, and why certain things are done in certain ways.
;
; First of all, DRI has a new policy for assembly language routines:  public
; names in them should not conflict with user public names, whether from a
; high level language or assembly language.  This is accomplished by having
; a special in-house version of RASM86 which permits '.' (period) in an
; identifier as any but the first character.  This startup routine uses that
; convention.  When CLEAR, the Common Language Environment And Runtime, is
; extended to all DRI languages, all internal (compiler referenced) runtime
; routines will contain a period, to avoid any conflict with a user name.
;
; This being the case, if you try to assemble this startup routine, you will
; get assembly errors.  So you must alter your RASM86 by patching it.  This
; is our way to insure that you really are a sophisticated user who knows what
; you are doing, otherwise you would not go to all this trouble.  Using SID86,
; read in RASM86.CMD.  The, using the SR (search) command, search for "$_?@".
; The byte before these four characters should be a hex 04, and the byte after
; should be a hex 00.  Change the hex 04 to a hex 05.  Change the hex 00 to a
; hex 2E (ASCII period).  Now write RASM86.CMD back out to the disk.  Period is
; now valid for the second and subsequent characters of an identifier.
;
; Now you can assemble this routine, or modify it.
; You MUST use the $nc (no case conversion) switch with RASM86.
;
; Note that the cseg is named 'cinit.' in lower case with a period in it.
; LINK86 puts this particular cseg FIRST in the .CMD file.  This means that
; if the compiler does not emit a MOD END (module end) record with a starting
; address, and if no assembly routine contains END START, where START is a
; label, then LINK86 will NOT put five bytes of JMPF (or JMP/NOP/NOP) in the
; file to jump to the START address, and control will come to the initializer.
; LINK86 also puts the dseg 'dinit.' first in the data area of the .CMD file.
; You must use the RASM86 $nc option to assemble;  otherwise the names will be
; CINIT. and DINIT., which LINK86 does not treat as special.
;
; This startup routine has been made modular for easy modification.
; There are basically six calls:  perform the segment relocation (omitted in
; small model), initialize the stack, initialize the heap, initialize the .CMD
; drive, initialize the zerodivide handler, and call _main which
; parses the command line passed to it, opens the standard files (performing
; I/O redirection), and calls main.
;
; This one startup routine is the common source for all memory models.  For
; example, 'retc' assembles to 'ret' in small model and to 'retf' in large model.
;
; The first file, clear.a86, provides the definitions that make model
; independent coding possible.
;
	nolist
;
;	This is a file of definitions written by Craig Franklin and
;	Bill Haygood and used throughout CLEAR.
;
C32	equ	0	; Small code model (use 1 for big model)
D32	equ	0	; Small data model (use 1 for big model)
CPM	equ	1	; Operating system
PCDOS	equ	0
;
;	Memory model determined by C32 and D32 defined above.
;	Operating System determined by CPM and PCDOS, defined there also.
;
;	Model		C32	D32
;	-----		---	---
;	Small		0	0	; Small code, small data
;	Compact		0	1	; Small code, large data
;	Medium		1	0	; Large code, small data
;	Large		1	1	; Large code, large data
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                   s t a c k   f r a m e   o f f s e t s		      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
     if	C32	;--------------------------------------------------------------
     if	D32	;------------------------------------------------------------ ;
ARG1	equ	8	; Offset from ÆBPÅ of caller argument #1	    ; ;
RAseg	equ	6	; Offset from ÆBPÅ of caller return address segment ; ;
RAoff	equ	4	; Offset from ÆBPÅ of caller return address offset  ; ;
SAVEDS	equ	2	; Offset from ÆBPÅ of caller DS slot		    ; ;
     else	; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; ;
ARG1	equ	6	; Offset from ÆBPÅ of caller argument #1	    ; ;
RAseg	equ	4	; Offset from ÆBPÅ of caller return address segment ; ;
RAoff	equ	2	; Offset from ÆBPÅ of caller return address offset  ; ;
     endif	;------------------------------------------------------------ ;
     else	; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
     if	D32	;------------------------------------------------------------ ;
ARG1	equ	6	; Offset from ÆBPÅ of caller argument #1	    ; ;
RAoff	equ	4	; Offset from ÆBPÅ of caller return address offset  ; ;
SAVEDS	equ	2	; Offset from ÆBPÅ of caller DS slot		    ; ;
     else	; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; ;
ARG1	equ	4	; Offset from ÆBPÅ of caller argument #1	    ; ;
RAoff	equ	2	; Offset from ÆBPÅ of caller return address offset  ; ;
     endif	;-----------------------------------------------------------; ;
     endif	;--------------------------------------------------------------
SAVEBP	equ	0	; Offset from ÆBPÅ of caller BP slot
SAVESP	equ	-2	; Offset from ÆBPÅ of my own SP slot
OVRAseg	equ	-4	; Offset from ÆBPÅ of my own true return address segment
OVRAoff	equ	-6	; Offset from ÆBPÅ of my own true return address offset
OVIDoff	equ	-8	; Offset from ÆBPÅ of my own overlay index
DISPLAY equ	-10	; Offset from ÆBPÅ of my lexical father frame
ONLINK	equ	-12	; Offset from ÆBPÅ of the previous on-frame
ONHEAD	equ	-14	; Offset from ÆBPÅ of the first on-unit for this frame
;
;	O/S Capability Definitions
;
multiuser	equ	8000h		; Multi-user capability bit
multitasking	equ	4000h		; Multi-tasking capability bit.
multisector	equ	2000h		; Multi-sector I/O capability bit.
date..time	equ	1000h		; Date/time capability bit.
networking	equ	0800h		; Networking capability bit.
cmdname		equ	0400h		; Capability to find .CMD file name
is8087		equ	0200h		; 8087 chip is present.
em8087		equ	0100h		; 8087 emulator is present and used.
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                             m o v e b y t e s			      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;	MOVEBYTES is a codemacro which generates code to move a string.
;	MOVEBYTES logically replaces REP MOVSB except for altering the flags.
;	MOVEBYTES takes 5 more bytes and is much faster for large CX.
;	Breakeven is about CX = 3, depending on the particular chip.
;
;	MOVEBYTES first moves an integral number of words and then moves the
;	(odd) last byte, if there is one.  Thus MOVEBYTES will run even faster
;	if either or both the source and target start on a word boundary.
;
;	Assumptions:
;
;		CX	=	number of bytes to be moved
;		DS:SI	->	source text address
;		ES:DI	->	destination text address
;
codemacro	MOVEBYTES
	db	0d1h			;	shr	cx,1
	db	0e9h
	db	0f3h			;	rep	movsw
	db	0a5h
	db	073h			;	jnc	even
	db	001h
	db	0a4h			;	movsb
	endm				; even:
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                              p a d b y t e s			      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;	PADBYTES stores the contents of the AX register into the destination.
;	PADBYTES exactly replaces REP STOSB except for altering the flags,
;	under the assumption that register AH = register AL.
;	PADBYTES takes 5 more bytes, and is much faster for large CX.
;	Breakeven is about CX = 3, depending on the particular chip.
;
;	PADBYTES first stores an integral number of words, and then stores
;	the (odd) last byte, if there is one.  Thus PADBYTES will run even
;	faster if the target is on a word boundary.
;	
;	Assumptions:
;
;		CX	=	number of copies of (AL) to store.
;		ES:DI	->	destination text address
;
codemacro	PADBYTES
	db	0d1h			;	shr	cx,1
	db	0e9h
	db	0f3h			;	rep	stosw
	db	0abh
	db	073h			;	jnc	even
	db	001h
	db	0aah			;	stosb
	endm				; even:
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                                   n i l				      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;	The NIL macro generates no code and accepts any argument types.
;
codemacro	NIL	src:Db
	endm
codemacro	NIL	src:Dw
	endm
codemacro	NIL	src:Eb
	endm
codemacro	NIL	src:Ew
	endm
codemacro	NIL	src:S
	endm
;
codemacro	NIL	dst:Eb,src:Db
	endm
codemacro	NIL	dst:Eb,src:Rb
	endm
;
codemacro	NIL	dst:Ew,src:Dw
	endm
codemacro	NIL	dst:Ew,src:Rw
	endm
codemacro	NIL	dst:Ew,src:S
	endm
;
codemacro	NIL	dst:Rw,src:Ew
	endm
;
codemacro	NIL	dst:S,src:Ew
	endm
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                c o d e   m o d e l   d e f i n i t i o n s		      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;	For large code model (C32 = 1), POPC and PUSHC generate POP and PUSH.
;	For small code model (C32 = 0), they generate nothing.
;
;	For large code model (C32 = 1), (CALLC,JMPC,RETC) generate (CALLF,JMPF,RETF).
;	For small code model (C32 = 0), (CALLC,JMPC,RETC) generate (CALL,JMP,RET).
;
     if	C32	;--------------------------------------------------------------
CALLC	equ	CALLF			; For medium and large models.	      ;
JMPC	equ	JMPF							      ;
POPC	equ	POP							      ;
PUSHC	equ	PUSH							      ;
RETC	equ	RETF							      ;
     else	; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
CALLC	equ	CALL			; For small and compact models.	      ;
JMPC	equ	JMP							      ;
POPC	equ	NIL							      ;
PUSHC	equ	NIL							      ;
RETC	equ	RET							      ;
     endif	;--------------------------------------------------------------
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                d a t a   m o d e l   d e f i n i t i o n s		      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;	For large data model (D32 = 1), LDX and LEX generate LDS and LES.
;	For small data model (D32 = 0), LDX and LEX generate MOV.
;
;	For large data model (D32 = 1), (MOVD,POPD,PUSHD) generate (MOV,POP,PUSH).
;	For small data model (D32 = 0), (MOVD,POPD,PUSHD) generate nothing.
;
     if	D32	;--------------------------------------------------------------
LDX	equ	LDS			; For compact and large models.	      ;
LEX	equ	LES							      ;
MOVD	equ	MOV							      ;
POPD	equ	POP							      ;
PUSHD	equ	PUSH							      ;
     else	; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
LDX	equ	MOV			; For small and medium models.	      ;
LEX	equ	MOV							      ;
MOVD	equ	NIL							      ;
POPD	equ	NIL							      ;
PUSHD	equ	NIL							      ;
     endif	;--------------------------------------------------------------
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                                 f r a m e				      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;	FRAME creates a stack frame in accordance with the memory model in use.
;	For small data model (D32 = 0), it does not "PUSH DS".
;	For large data model (D32 = 1), it does.
;	If immediate data is specified, it must be less than 128 bytes.
;
codemacro	FRAME
     if	D32	;--------------------------------------------------------------
	db	01eh			;	push	ds		      ;
     endif	;--------------------------------------------------------------
	db	055h			;	push	bp
	db	08bh			;	mov	bp,sp
	db	0ech
	endm
;
codemacro	FRAME	imm.data:Db
     if	D32	;--------------------------------------------------------------
	db	01eh			;	pushd	ds		      ;
     endif	;--------------------------------------------------------------
	db	055h			;	push	bp
	dw	0ec83h			;	sub	sp,imm.data
	db	imm.data
	dw	0ec8bh			;	mov	bp,sp
	endm
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                               u n f r a m e				      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;	UNFRAME release the stack frame created by FRAME above.
; 	For small data model (D32 = 0), it does not do a POP DS;
;	for large data model (D32 = 1), it does a POP DS before it returns.
;	For large code (C32=1) it does a RETF instead of RET.
;
codemacro	UNFRAME
	db	05dh			;	pop	bp
     if	D32	;--------------------------------------------------------------
	db	01fh			;	pop	ds		      ;
     endif	;--------------------------------------------------------------
     if	C32	;--------------------------------------------------------------
	db	0cbh			;	retf			      ;
     else	; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
	db	0c3h			;	ret			      ;
     endif	;--------------------------------------------------------------
	endm
;
codemacro	UNFRAME	imm.data:Db
	dw	0668dh			;	lea	sp,imm.dataÆbpÅ
	db	imm.data
	db	05dh			;	pop	bp
     if	D32	;--------------------------------------------------------------
	db	01fh			;	pop	ds		      ;
     endif	;--------------------------------------------------------------
     if	C32	;--------------------------------------------------------------
	db	0cbh			;	retf			      ;
     else	; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
	db	0c3h			;	ret			      ;
     endif	;--------------------------------------------------------------
	endm
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                                   s y s				      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;	SYS loads the CL register (for CP/M) or AH register (for PCDOS) with
;	the system call number specified as an argument and generates a call
;	to the operating system.  The argument may be an immediate byte value,
;	a byte register, or a byte memory address.  The ES register is
;	preserved for small data model under CP/M.  (PCDOS does not alter it.)
;
codemacro	SYS	src:Db
     if	CPM	;--------------------------------------------------------------
	db	0b1h			;	mov	cl,---		      ;
	db	src							      ;
     if	D32 eq 0;--------------------------------------------------------     ;
	db	06			;	push	es		;     ;
     endif	;--------------------------------------------------------     ;
	db	0cdh			;	call	cpm		      ;
	db	0e0h							      ;
     if	D32 eq 0;--------------------------------------------------------     ;
	db	07			;	pop	es		;     ;
     endif	;--------------------------------------------------------     ;
     endif	;--------------------------------------------------------------
     if PCDOS	;--------------------------------------------------------------
	db	0b4h			;	mov	ah,---		      ;
	db	src							      ;
	db	0cdh			;	call	pcdos		      ;
	db	021h							      ;
     endif	;--------------------------------------------------------------
	endm
;
codemacro	SYS	src:Rb
	db	08ah			;	mov	Æah/clÅ,R
     if	CPM	;--------------------------------------------------------------
	dbit	5(19h),3(src(0))	;	mov	cl,R		      ;
     if	D32 eq 0;--------------------------------------------------------     ;
	db	06h			;	push	es		;     ;
     endif	;--------------------------------------------------------     ;
	db	0cdh			;	call	cpm		      ;
	db	0e0h							      ;
     if	D32 eq 0;--------------------------------------------------------     ;
	db	07h			;	pop	es		;     ;
     endif	;--------------------------------------------------------     ;
     endif	;--------------------------------------------------------------
     if PCDOS	;--------------------------------------------------------------
	dbit	5(1ch),3(src(0))	;	mov	ah,R		      ;
	db	0cdh			;	call	pcdos		      ;
	db	021h							      ;
     endif	;--------------------------------------------------------------
	endm
;
codemacro	SYS	src:Eb
	segfix	src
	db	8ah			;	mov	---,qÆbpÅ
     if	CPM	;--------------------------------------------------------------
	modrm	1,src			;	mov	cl,qÆbpÅ	      ;
     if	D32 eq 0;--------------------------------------------------------     ;
	db	06h			;	push	es		;     ;
     endif	;--------------------------------------------------------     ;
	db	0cdh			;	call	cpm		      ;
	db	0e0h							      ;
     if	D32 eq 0;--------------------------------------------------------     ;
	db	07h			;	pop	es		;     ;
     endif	;--------------------------------------------------------     ;
     endif	;--------------------------------------------------------------
     if PCDOS	;--------------------------------------------------------------
	modrm	4,src			;	mov	ah,qÆbpÅ	      ;
	db	0cdh			;	call	pcdos		      ;
	db	021h							      ;
     endif	;--------------------------------------------------------------
	endm
	list
;ACF	Name			'MINIT'
;ACF	Title			'MINIT for DRC V1.11'
;ACF	Pagesize		75
;
;	File name:		MINIT.A86
;
;	Module name:		MINIT
;
;	Entry parameters:	None.
;
;	Return value:		None.
;
;	Entry point		Arguments	Function
;	-----------		---------	--------
;	m.init			None.		Initialize the Common Lanugage
;						Environment And Runtime (CLEAR).
;	Algorithm:		
;				Relocate the segment references if O/S has not
;					(not for small model).
;				Initialize the stack.
;				Initialize the heap.
;				Initialize the command name drive.
;				Initialize the 8087 or 8087 emulator (not for DRC).
;				Address the command tail and call _main.
;
	eject
;ACF	include	CLEAR			; Include CLEAR definitions.
;
     if C32 eq 0;--------------------------------------------------------------
CGROUP	GROUP	cinit.							      ;
     endif	;--------------------------------------------------------------
;
cinit.   cseg
;
;ACF	extrn	m.init.stack:	near
;ACF	extrn	m.init.heap:	near
;ACF	extrn	m.init.cmd:	near
;ACF	extrn	m.init.hardware.error:near
;ACF	extrn	m.init.os:	near
	extrn	osattr:		far
	extrn	_main:		far
	extrn	main:		far
;
	public  m.init
	public	_exit
	public	m.init.error
	public	m.error
;
m.init: 
     if	D32 or C32	;-----------------------------------------------------
;ACF	extrn	m.init.reloc:near
	call	m.init.reloc	; Eliminate the R command.
     endif		;-----------------------------------------------------
	call	m.init.stack	; Initialize the stack.
	call	m.init.heap	; Initialize the heap.
	call	m.init.cmd	; Find .CMD drive for overlay manager.
	call	m.init.hardware.error	; Initialize the zero divide handler.
	call	m.init.os	; Find out which version of the operating system.
;
; The following call is for Fortran 77 only, not for DRC.
;
     if	0	;--------------------------------------------------------------
	extrn	m.init.8087:	near
	call	m.init.8087	; Initialize the 8087 or 8087 emulator.
     endif	;--------------------------------------------------------------

				; Note: above calls can be short because all
				; call targets use cinit. cseg in them.
	callc	osattr		; Find O/S attributes.
				;
        mov     si,80h          ; Offset of command line
        lodsb			; AL = length of command line.
        xor     ah,ah
        push    ax
	pushd	ds		; Push DS if D32 (large data model)
        push    si
        callc   _main
;
_exit:
;
if CPM	;----------------------------------------------------------------------
	SYS	0		; Exit to O/S.
endif	;----------------------------------------------------------------------
;
if PCDOS;----------------------------------------------------------------------
	mov	ds,ss:.9	; DS = original DS from O/S.
	push	word ptr .40h	; Push CS for INT 20
	sub	ax,ax
	push	ax		; Push IP (= 0) for INT 20
	retf			; Return to PCDOS INT 20 instruction
;
endif	;----------------------------------------------------------------------
	jmpc	main		; For debugging.
;
m.init.error:			; Near call followed by fatal error message.
	popd	dx
	pushd	cs
	pushd	dx
;
m.error:			; Far call followed by fatal error message.
	pop	dx		; DS:DX -> error message text.
if D32 eq 0
	push	cs
endif
	pop	ds
	SYS	9		; BDOS function 9 prints the error message.
	jmps	_exit		; Return to O/S.
;
; Dummy out _v_reloc_8087 for overlay manager
;
	public	_v_reloc_8087
_v_reloc_8087:
	retc			; Return
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                                  D A T A				      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
DGROUP	GROUP	DATA,dinit.
;
dinit.	dseg
;
	public	offset.8087
;
offset.8087 dw	0		; Offset from SS: of 8087 reentrant data area.
				; MUST BE FIRST IN DATA AREA FOR 8087 EMULATOR.
;
	dseg
;
;ACF	end
;ACF	Name			'MINITRELOC'
;ACF	Title			'M.INIT.RELOC'
;ACF	Pagesize 		75
;
;	File name:		MINITREL.A86
;
;	Module name:		MINITRELOC
;
;	Entry parameters:	Stack exists.  DS:0 -> base page.
;
;	Return value:		None.
;
;	Errors:			Must use R command or LINK86 V1.2 with this O/S
;
;	Entry point		Arguments
;	-----------		---------
;	m.init.reloc		None.
;
;	m.init.reloc.buffer	Pointer to null terminated relocation buffer.
;
;	_v_reloc_segs		Pointer to null terminated relocation buffer.
;				Pointer to array of 8 overlay segment bases.
;				Byte containing valid target relocation groups.
;
;	Function:		Relocate segment references in a program/overlay.
;				WARNING: program must be linked by LINK86 V1.2.
;
	eject
;ACF	include	clear			; Get CLEAR definitions.
;
cinit.	cseg
;
;ACF	public	m.init.reloc
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                       O F F S E T S   F R O M   B P			      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
OSDS		equ	2		; Original DS from OS -> base page.
;		equ	0		; Caller BP
SIDI		equ	-4		; Space to save SI and DI.
loadsegs	equ	SIDI-2		; Mask of segments to relocate.
overbases	equ	loadsegs -16	; 8 group bases from overlay header.
reloc.return	equ	overbases-2	; Return address for reloc.buffer
rootbases	equ	reloc.return-16	; 8 group bases from program base page.
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                          m . i n i t . r e l o c			      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;ACF	extrn	m.init.error:	near
;
m.init.reloc:
	mov	cx,seg m.init.reloc	; Get a relocatable segment reference.
	jcxz	need_relocation		; Relocation done already ?
	ret				; Yes, return to caller.
;
need_relocation:
	mov	cx,.45			; CX = Aux Group 4 base address.
	jcxz	old_LINK86		; If 0, must be LINK86 before V1.2
;
;	Relocate the root using Aux Group 4
;
	push	es			; Save caller ES.
	push	ds			; Save caller DS.
	push	bp			; Save caller BP.
	mov	bp,sp			; Create new stack frame.
	mov	ax,-1			; AX = ffffh = LOADSEGS = relocate all segments.
	push	ax			; Pretend to save SI and DI
	push	ax			; to synchronize with _v_reloc_segs.
	push	ax			; Push LOADSEGS = ffffh
	call	pushbase		; Push the group start addresses.
	mov	ds,cx			; DS:SI-> AUX GROUP 4
	sub	si,si
	call	reloc.buffer		; Do it all in only one call.
	mov	sp,bp			; Reset SP.
	pop	bp			; Restore caller BP.
	pop	ds			; Restore caller DS.
	pop	es			; Restore caller ES.
	ret				; Return to caller.
;
old_LINK86:
	call	 m.init.error
	db	'You must link with LINK86 V1.2 or later.',0dh,0ah,'$'
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                               _ v_ r e l o c			      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;					; +2 below for PUSH SS:.9
BUFFER		equ	ARG1+2		; Offset from ÆBPÅ of buffer address.
OVERBASE	equ	BUFFER  +2+2*D32; Offset from ÆBPÅ of overlay bases.
LOADSEGS	equ	OVERBASE+2+2*D32; Offset from ÆBPÅ of valid targets.
;
	public	_v_reloc_segs
;
_v_reloc_segs:
	pushd	ds			; Save caller DS
	push	ss:word ptr .9		; Push original DS from O/S.
	push	bp			; Save caller BP
	mov	bp,sp			; Address argument.
	push	si			; Save caller SI.
	push	di			; Save caller DI.
	push	word ptr LOADSEGSÆbpÅ	; Push loadsegs for reloc.buffer.
;
;	Push the overlay group start addresses
;
	ldx	si,OVERBASEÆbpÅ		; DS:SI -> overlay bases from caller.
; TEMPORARY -- must always do this for large model.  Must TEMPORARILY do it
; for small model until ES is always = SS.  Uncomment if/endif when true.
;if	D32	;--------------------------------------------------------------
	push	ss			; ES:DI -> stack frame overlay bases.
	pop	es
;endif	;--------------------------------------------------------------
	lea	di,overbasesÆbpÅ
	mov	sp,di			; Allocate space
	mov	cx,8			; 8 groups	rep	movsw
;
;	Relocate the buffer
;
	ldx	si,BUFFERÆbpÅ		; DS:SI -> relocation buffer
	call	reloc.buffer		; Process the relocation buffer
	lea	sp,0-4ÆbpÅ		; Reset SP.
	pop	di			; Restore caller DI.
	pop	si			; Restore caller SI.
	pop	bp			; Restore caller BP.
	pop	cx			; Pop off original DS from O/S.
	popd	ds			; Restore caller DS.
	retc
	eject
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *	Subroutine to push the base page group start addresses		      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
pushbase:
	pop	bx			; BX = return address.
	mov	dx,ds			; DX = caller DS.
	mov	ds,OSDSÆbpÅ		; DS from O/S, points to base page.
	push	word ptr .45
	push	word ptr .39
	push	word ptr .33
	push	word ptr .27
	push	word ptr .21
	push	word ptr .15
	push	word ptr .09
	push	word ptr .03
;
	mov	ds,dx			; DS = caller DS.
	push	bx
	ret				; Return
	eject
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *         P R O C E S S   O N E   R E L O C A T I O N   B U F F E R	      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;	Register usage:
;
;	(AX)	Temporary.
;	(BX)	Byte offset in paragraph.
;	(CX)	Shift count.
;	(DX)	Segment base to add to memory.
;	(DI)	Temporary.
;	(BP)	Frame pointer to address loadsegs byte and two base tables
;	(DS:SI)	Relocation buffer entry.
;	(ES:BX)	Memory word to relocate.
;
reloc.buffer:
	call	pushbase		; Push the root base addresses.
	push	si			; Save caller SI.
	sub	ax,ax			; AX = 0 (for first LODSB).
	sub	cx,cx			; CX = 0.
	jmps	reloc.element.into	; Jump into loop.
;
reloc.element.loop:
;
;	Set DX = source group base
;
	sub	al,11h			; Convert 1-8/1-8 to 0-7/0-7.
	mov	di,ax			; DI = AX.
	and	di,0007h		; DI = source group number (0-7).
	add	di,di			; DI = source group number * 2.
	mov	dx,rootbasesÆdi+bpÅ	; DX = source group base.
;
;	Set DI = target group base
;
	and	al,70h			; AX = target group number * 16.
	shr	al,1			; AX = target group number *  8.
	shr	al,1			; AX = target group number *  4.
	shr	al,1			; AX = target group number *  2.
	mov	di,ax			; DI = target group number *  2.
	mov	di,overbasesÆdi+bpÅ	; DI = target group base.
;
;	Set BL = byte with a 1 bit in it for the target group
;
	shr	al,1			; AX = target group number *  1.
	mov	cl,al			; CX = target group number.
	mov	bl,1			; BL = 1 for shift
	shl	bl,cl			; BL = mask with 1 for target segment
;
;	Compute address of memory word to add DX to
;
	lodsw				; AX = paragraph offset of memory word
	add	di,ax			; DI = segment base of memory word
	mov	es,di			; ES = DI
	sub	ax,ax			; Clear AX for LODSB.
	lodsb				; AL = byte offset of memory word
	test	bl,loadsegsÆbpÅ		; OK to relocate target segment?
	jz	reloc.element.into	; No.
	mov	bx,ax			; BX = byte offset
	add	es:ÆbxÅ,dx		; Relocate memory word.
;
reloc.element.into:
	lodsb				; AL = group number
	test	al,0f0h			; End of buffer or fixup list ?
	jnz	reloc.element.loop	; No.
;
	sub	ax,ax			; Assume return false (done).
	pop	bx			; BX = input SI
	sub	si,bx			; SI = number of bytes processed.
	sub	si,129			; Full buffer processed?
	jnz	reloc.element.return	; No,  return 0 (last buffer).
	inc	ax			; Yes, return 1 (more to come).
;
reloc.element.return:
if	D32 eq 0;--------------------------------------------------------------
	push	ss			; Reset ES = SS for small model.
	pop	es
endif		;--------------------------------------------------------------
	lea	sp,reloc.returnÆbpÅ	; Prepare to return.
	ret				; Return.
;
;ACF	end
;ACF	Name			'MINITSTACK'
;ACF	Title			'M.INIT.STACK'
;ACF	Pagesize		75
;
;	File name:		MINITSTA.A86
;
;	Module name:		M.INIT.STACK
;
;	Entry parameters:	None.
;
;	Return value:		None.
;
;	Entry point		Arguments	Function
;	-----------		---------	--------
;
;	m.init.stack		None.		Initialize the CLEAR stack.
;
;	_salloc			int n		Allocate n bytes on the stack.
;
;	Algorithm:		With interrupts disabled (to allow for the
;				defective versions of the 8088), set SS:SP, SL.
;
;				Small model:	Set SS = DS.  Set SP from .6,
;						the top of the DGROUP.
;						SL. = HP. in minithea.a86.
;
;				Large model:	Set SS:SP from the base page.
;						SL. is assembled in.
;				
	eject
;ACF	include	clear			; Get CLEAR definitions.
;
     if C32 eq 0;--------------------------------------------------------------
CGROUP	GROUP	cinit.							      ;
     endif	;--------------------------------------------------------------
;
cinit.	cseg
;
;ACF	extrn	m.init.error: near
;
	public	m.init.stack, _salloc
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                          M . I N I T . S T A C K			      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
m.init.stack:
	pop	ax			; Pop m.init return address.
	pop	cx			; Pop system return address (this is a
	pop	dx			; 32-bit address even in small model!).
;
;	Disable interrupts to set SS:SP.
;
	sub	bx,bx			; BX = 0
     if	D32	;--------------------------------------------------------------
	pushf
	pop	si			; Save current status and flags.
	cli				; Disable interrupts.
	mov	ss,15hÆbxÅ		; Setup stack segment register.
	mov	sp,12hÆbxÅ		; Set stack offset.
					; SL. is already set by assembly.
	push	si
	popf				; Restore status and flags
     else
	push	ds			; SS = DS
	pushf
	pop	si			; Save current status and flags.
	cli				; Disable interrupts.
	pop	ss
	mov	sp,6ÆbxÅ		; Initialize SP from base page.
					; SL. is defined equ HP. (minithea.a86)
	push	si
	popf				; Restore status and flags
     endif	;--------------------------------------------------------------
	inc	sp			; Use all available allocated memory.
	and	sp,0fffeh		; Align for iAPX-286 speed.
	eject
;
;	Now construct the first stack frame.
;
	push	dx			; Push system return address (this is a
	push	cx			; 32-bit address even in small model!).
	push	bx			; No previous stack frame.
	mov	bp,sp			; Establish the first stack frame.
	lea	dx,-8ÆbpÅ		; First stack frame is 8 words long.
	push	dx			; Set SAVESP
	push	bx			; Set ENLINK = 0 (no previous environment)
	push	bx			; Set ONLINK = 0 (no previous on frame)
	push	bx			; Set ONFRAME = 0 (no on units in frame)
	push	ax			; Push m.init return address
     if	D32	;--------------------------------------------------------------
	mov	ss:.0,ds		; For large model to load for big model
     endif	;--------------------------------------------------------------
	mov	ss:.9,ds		; All memory models can now use ss:.9!
	ret				; Return.
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                         _ s a l l o c				      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
_salloc:				; Allocate N bytes on the stack.
	pop	bx			; Pop return address.
	popc	cx
	pop	dx			; Pop N.
	inc	dx			; Round N to even.
	and	dl,0feh
     if	D32	;--------------------------------------------------------------
	mov	ax,seg SL.
	mov	es,ax
	mov	ax,dx			; AX = N.
	add	ax,es:SL.		; AX = SL. + N
     else	; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
	mov	ax,dx			; AX = N.
	add	ax,SL.			; AX = SL. + N
     endif	;--------------------------------------------------------------
	cmp	ax,sp			; Would stack overflow?
	jbe	stackok			; No.
	call	m.init.error		; Yes, fatal error.
	db	'Stack overflow$'
;
stackok:
	sub	sp,dx			; Allocate N bytes.
	mov	ax,sp			; SS:AX -> N bytes on stack.
	push	dx			; Push N.
	pushc	cx			; Push return address
	push	bx
     if	D32	;--------------------------------------------------------------
	mov	bx,ss			; BX = SS for large model return value.
     endif	;--------------------------------------------------------------
	retc				; Return BX:AX -> N bytes on stack.
	eject
     if	D32	;--------------------------------------------------------------
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                                  D A T A				      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
DGROUP	GROUP	dinit.
;
dinit.	dseg
;
	public	SL.
;
SL.		dw	14		; Stack limit. Bias of 14 is for string routines.
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *               S T A C K   S T O R A G E   A L L O C A T I O N	      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;
sinit.	sseg	word							      ;
;									      ;
	dw	0			; Old OSDS -- TEMPORARY.	      ;
	rb	7							      ;
DSOS	dw	0			; DS value from O/S.		      ;
					; Large model -- ss:.9 is here.	      ;
					; Small model -- ss:.9 is base page   ;
;
stack.	sseg	word							      ;
;
;	public	ONFRAME			; Wait for PL/I to implement this.    ;
;									      ;
;ONFRAME	dw	0						      ;
;	dw	seg ONFRAME						      ;

     else	; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
;ACFDGROUP	GROUP	dinit.
;ACFdinit.	dseg
;ACF	extrn	SL.:word
     endif	;--------------------------------------------------------------
;
;ACF	end
;ACF	Name			'MINITHEAP'
;ACF	Title			'M.INIT.HEAP'
;ACF	Pagesize 75
;
;	File name:		MINITHEA.A86
;
;	Module name:		MINITHEAP
;
;	Entry point		Arguments		Function
;	-----------		---------		--------
;
;	m.init.heap		None.			Initialize the heap.
;
;	nbrk			None			Return the remaining
;							heap size in bytes.
;							Return (long)(HL.-HP.)
;
;	sbrk			int n			Extend the heap n bytes.
;							If HP. + n <= HL.,
;							set HP. = HP. + n
;
;	brk			char *p			If HP. <= p <= HL.,
;							set HP. = p
;
;	Algorithm:	
;
;		m.init.heap:
;
;			Large:	Set HP. to point to ESEG.
;				Set HL. to point to HP. + size of ESEG.
;
;			Small:	Set HP. to point to the heap at the bottom of
;			the free area.  The stack is located at the top of the
;			free area.  Equivalence HL. and SL., the stack limit.
;
;		nbrk:	Set R = HP. - HL., if D32 set R *= 16, return R.
;
;		sbrk:	Round request r to bytes or paragraphs, set R = P = HP.,
;			set P = P+r, if P <= HL., set HP. = R and return R.
;
;		brk:	Compare pointer argument P to HP. and HL.
;			If P >= HP. and P <= HL., set HP. = P, and
;			return 0 (success), else return -1 (failure).
;
;		In all of the above routines, HP. and HL. are one word
;		pointers into the heap whose units are paragraphs.
;		When sbrk returns the old HP., it is converted to a
;		pointer with offset 0 in the large model.
;		This is so the caller can use a full 64K byte offset with it.
;
	eject
;ACF	include	clear			; Get CLEAR definitions.
;
     if	D32 eq 0;--------------------------------------------------------------
slack	equ	256			; Allow for additional stack.
     endif	;--------------------------------------------------------------
;
cinit.	cseg
;
	public	m.init.heap, nbrk, sbrk, brk
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                           m . i n i t . h e a p			      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
m.init.heap:
     if	D32	;--------------------------------------------------------------
	mov	HP.,es			; Initialize HP. (LINK86 bug).
	mov	ax,.0ch			; AX = low word  of Extra Segment size.
	mov	dh,.0eh			; DH = high byte of Extra Segment size.
	add	ax,15			; Convert offset to paragraphs.
	jnc	m.init.heap.nc		; Jump if not 64K boundary.
	inc	dh			; 64K boundary.  Increment high order.
;
m.init.heap.nc:
	and	al,0f0h			; Round bytes to paragraphs.
	mov	cl,4			; CL = 4
	shr	ax,cl			; Convert to paragraph number.
	shl	dh,cl			; Convert to paragraph number.
	add	ah,dh		   ; AX = paragraph number of heap size
	add	ax,HP.			; AX = paragraph number of heap limit
	mov	HL.,ax			; Set heap limit
     else
	push	ds			; ES = DS
	pop	es
	mov	ax,?MEMRY		; Set up heap for brk().
	add	ax,15
	and	ax,0fff0h		; Paragraph align.
	mov	HP.,ax
     endif	;--------------------------------------------------------------
	ret
	eject
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                                  n b r k				      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;LONG	nbrk()					/* CLEAR FUNCTION ***********/
nbrk:
     if	D32	;--------------------------------------------------------------
	mov	ax,seg HP.		; AX = seg HP.
	mov	es,ax			; Set ES = seg HP.
	mov	ax,es:HL.		; AX = heap limit.
	sub	ax,es:HP.		; AX = heap size = heap limit - heap base.
	mov	bx,16
	mul	bx			; Convert paragraphs to long int bytes.
	mov	bx,dx			; In AX/BX.
	retc				; Return.
     else	; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
	mov	ax,sp			; AX = heap limit.
	sub	ax,slack		; Allow for additional stack.
	sub	ax,HP.
	sub	bx,bx			; Return long int bytes.
	retc				; Return.
     endif	;--------------------------------------------------------------
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                                  s b r k				      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;BYTE *	sbrk(Num)				/* CLEAR FUNCTION ***********/
sbrk:
     if	D32	;--------------------------------------------------------------
	mov	bx,sp			; Address argument
	mov	dx,ss:2+2*C32ÆbxÅ	; Get allocation size in bytes.
	add	dx,15			; Round up to next paragraph.
	and	dl,0f0h
	mov	cl,4			; CL = 4
	shr	dx,cl			; Convert bytes to paragraphs
	push	ds			; Save caller DS (large model)
	mov	bx,seg HP.		; BX = DS of HP.
	mov	ds,bx			; Set DS
	mov	bx,HP.			; BX = old heap pointer (in paragraphs)
	sub	ax,ax			; BX:AX = old HP.:0 = pointer to area
	add	dx,bx			; DX = new heap pointer (in paragraphs)
	cmp	dx,HL.			; Will it fit ?
	ja	xbrk.fail		; No.  Fail.
	mov	HP.,dx			; Update HP.
	pop	ds			; Restore original DS.
	retc				; Return BX:AX = old HP.:0.
;
xbrk.fail:				; Set AX = -1 (failure) and return.
	mov	ax,-1			; AX = -1
	mov	bx,ax
	pop	ds			; Restore original DS.
	retc				; Return.
;
     else
	mov	bx,sp			; BX = SP
	mov	bx,ss:2+2*C32ÆbxÅ	; Get argument.
	inc	bx			; Round up to even byte boundary.
	and	bl,0feh
	mov	ax,HP.			; Get current heap pointer.
	add	bx,ax			; Did wrap around occur ?
	jc	xbrk.fail		; Yes.
	jmps	xbrk
;
xbrk.fail:				; Set AX = -1 (failure) and return.
	mov	ax,-1			; AX = -1
	ret				; Return.
     endif	;--------------------------------------------------------------
	eject
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *				     b r k				      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;BYTE *	brk(HeapPtr)				/* CLEAR FUNCTION ***********/
brk:
     if	D32	;--------------------------------------------------------------
	mov	bx,sp			; BX = SP
	push	ds			; Save caller DS (large model)
	mov	ax,ss:2+2*C32ÆbxÅ	; AX = pointer offset
	mov	bx,ss:4+2*C32ÆbxÅ	; BX = pointer segment
	add	ax,15			; Round AX from bytes to paragraphs
	jnc	brk.ok			; Carry ?
	add	bx,1000h		; Yes, add 64K bytes to segment.
;
brk.ok:
	mov	cl,4			; CL = 4
	shr	ax,cl
	add	ax,bx			; And add in segment
	cmp	ax,HP.			; Below current heap pointer?
	jb	xbrk.fail		; Yes.  Fail.
	cmp	ax,HL.			; Above heap limit?
	ja	xbrk.fail		; Yes.  Fail.
	mov	HP.,ax			; Reset heap pointer
	sub	ax,ax			; Succeed.
	pop	ds			; Restore caller DS
     else
	mov	bx,sp
	mov	bx,ss:2+2*C32ÆbxÅ	; Get parameter - brk address.
	sub	ax,ax			; AX = 0 for success
;
xbrk:
	mov	cx,sp			; CX = SP
	sub	cx,slack		; Allow for additional stack.
	cmp	bx,cx			; Below stack pointer ?
	jae	xbrk.fail		; No.
	cmp	bx,HP.			; Above heap pointer ?
	jb	xbrk.fail		; No.
	mov	HP.,bx			; Set new heap pointer.
     endif	;--------------------------------------------------------------
	retc				; Return.
	eject
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                                  D A T A				      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
DGROUP	GROUP	dinit.
dinit.	dseg
;
     if	D32	;--------------------------------------------------------------
HP.	dw	0 			; Heap pointer in paragraphs.	      ;
HL.	dw	0			; Heap limit in paragraphs.	      ;
;					; (Set by m.init.heap.)		      ;
heap.	eseg								      ;
;									      ;
ES.	rw	0							      ;
     else	; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
	public	?MEMRY, HP., SL.					      ;
?MEMRY	rw	1			; Initialized by LINK86.	      ;
HP.	rw	1			; Heap pointer in bytes.	      ;
SL.	equ	HP.			; Is also stack limit in bytes.	      ;
     endif	;--------------------------------------------------------------
;
;ACF	end
;ACF	Name			'MINITCMD'
;ACF	Title			'M.INIT.CMD'
;ACF	Pagesize 75
;
;	File name:		MINITCMD.A86
;
;	Module name:		MINITCMD
;
;	Arguments:		None.
;
;	Return value:		_cmd_drive_bin		.CMD drive in binary
;				_cmd_drive_asc		.CMD drive in ASCII
;
;	Function:		To determine the .CMD file drive.
;
;	Algorithm:		Look at location 50h in the base page.
;				If it is non-zero, it is the binary .CMD drive.
;				If it is zero, get the current drive from BDOS.
;				In either case, add 'A' to get the ASCII drive.
;
	eject
;ACF	include	clear			; Get CLEAR definitions.
;
curdrive	equ	25		; BDOS call to return current drive.
;
     if C32 eq 0;--------------------------------------------------------------
CGROUP	GROUP	cinit.							      ;
     endif	;--------------------------------------------------------------
;
cinit.	cseg
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                             m . i n i t . c m d			      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
	public	m.init.cmd
;
m.init.cmd:
;
     if	CPM	;--------------------------------------------------------------
	SYS	12			; get O.S. version number
	cmp	ah,11h			; MPM-86?
	jne	m.aft.os.check		; nope
	inc	byte ptr .50h		; fix for MPM
m.aft.os.check:
;
	mov	al,.50h			; AL = CMD drive number (1 to 16 or 0)
	test	al,al			; Special CMD drive = 0 case?
	jz	m.init.cmd.current.drive; Yes.
	dec	al			; AL = 0 to 15.
	cmp	al,15			; 1 <= CMD drive <= 16 case?
	jbe	m.init.cmd.drive	; Yes, trust it.
     endif	;--------------------------------------------------------------

m.init.cmd.current.drive:		; Use system current drive:
	SYS	curdrive		; AL = 0 to 15 for A to P.
;
m.init.cmd.drive:
	mov	_cmd_drive_bin,al	; Store drive in binary.
	add	al,'A'			; Convert it to ASCII.
	mov	_cmd_drive_asc,al	; Store drive in ASCII.
	ret				; Return.
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                                  D A T A				      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
DGROUP		GROUP	_CMD_DRIVE_BIN,_CMD_DRIVE_ASC
;
_CMD_DRIVE_BIN	dseg	common
		public	_cmd_drive_bin
_cmd_drive_bin	db	0
;
_CMD_DRIVE_ASC	dseg	common
		public	_cmd_drive_asc
_cmd_drive_asc	db	0
;
;ACF	end
;ACF	Name			'MINITERROR'
;ACF	Title			'M.INIT.ERROR'
;ACF	Pagesize 75
;
;	File name:		MINITER.A86
;
;	Module name:		MINITERROR
;
;	Entry parameters:	None.
;
;	Return value:		None.
;
;	Entry point		Arguments
;	-----------		---------
;
;	m.init.hardware.error	None.
;
;	Function:		To initialize the runtime system integer zero
;				divide error handler.
;
;	Algorithm:		Place the vector to the integer zero divide
;				handler in absolute location 0:0.
;
	eject
;ACF	include	clear			; Get CLEAR definitions.
;
     if C32 eq 0;--------------------------------------------------------------
CGROUP	GROUP	cinit.							      ;
     endif	;--------------------------------------------------------------
;
cinit.	cseg
;
;ACF	extrn	m.init.error: near
;
	public	m.init.hardware.error
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                   m . i n i t . h a r d w a r e . e r r o r		      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;	Initialize the zero divide vector.
;
m.init.hardware.error:
	push	ds			; Save original DS.
	sub	bx,bx			; BX -> offset 0
	mov	ds,bx			; DS = 0
	mov	ÆbxÅ,offset zerodiv	; Store the zero divide handler pointer
	mov	2ÆbxÅ,cs		;	at hardware locations 0 and 2.
	pop	ds			; Restore original DS.
	ret				; Return.
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                               z e r o d i v				      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;	Integer zero divide handler.
;
zerodiv:
	call	m.init.error		; Fatal error
	db	'Zero divide error$'
;
;ACF	end
;ACF	Name			'M.INIT.OS'
;ACF	Title			'M.INIT.OS'
;ACF	Pagesize 75
;
;	File name:		MINITOS.A86
;
;	Module name:		M.INIT.OS
;
;	Arguments:		None.
;
;	Return value:		_os_version	= 0 (unrecognized OS)
;						= 1 - 21h (non-CP/M OS's)
;						= 22h (CP/M-86 v. 2.2)
;						= 23h (MP/M-86 v. 3.0)
;						= 24h (CCP/M-86 v. 3.0)
;
;				_os_ability	= inclusive OR of:
;						8000h (multi-user)
;						4000h (multi-tasking)
;						2000h (multi-sect I/O)
;						1000h (date/time)
;						0800h (networking)
;						0400h (cmd name available)
;						0200h (8087 is present)
;
;	Entry Point		Arguments
;	-----------		---------
;	m.init.os		None
;
;	Function:		To determine the OS version and capabilities.
;
;	Algorithm:		Call the operating to obtain the OS
;				type/version and the date/time, if present.
;
;	Attributes:		OSIF (O/S interface routine)
;
	eject
;ACF	include	clear			; Get CLEAR definitions.
;
version		equ	12		; BDOS call to return version.
date.time	equ	105		; BDOS call to return date/time.
;
     if C32 eq 0;--------------------------------------------------------------
CGROUP	GROUP	cinit.							      ;
     endif	;--------------------------------------------------------------
;
cinit.	cseg
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                             m . i n i t . o s			      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
	public	m.init.os
;
m.init.os:
	if PCDOS;--------------------------------------------------------------
	ret		; Proper attributes are assembled in.		      ;
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                                  D A T A				      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
DGROUP		GROUP	_OS_ABILITY,_OS_VERSION
;
_OS_ABILITY	dseg	common
		public	_os_ability
_os_ability	dw	multisector+date..time
;
_OS_VERSION	dseg	common
		public	_os_version
_os_version	db	0
;
	endif	;--------------------------------------------------------------
;
	if CPM	;--------------------------------------------------------------
;
;	Determine whether the operating system supports date/time.
;
	pushd	ds			; Save caller DS.
	pushd	ss
	popd	ds
	sub	sp,4			; Allocate space for date/time.
	mov	dx,sp
	SYS	date.time
	add	sp,4			; Free date/time space.
	popd	ds			; Restore caller DS.
	inc	ax			; AX = -1? (No date/time).
	jz	m.init.os.notime	; Yes.
	sub	ax,ax			; AX = 0.
	or	ax,date..time		; Set the date/time capability bit.
;
m.init.os.notime:
;
;	Get the O/S version
;
	push	ax
	SYS	version			; Get the O/S version in BX
	pop	ax
	cmp	bx,22h			; Is the version less than 22h ?
	jb	m.init.os.found		; Yes.
;
;	Determine whether the operating system supports networking.
;
	test	bh,2			; Is networking available ?
	jz	m.init.os.nonet		; No.
	or	ax,networking		; Yes, set its capability bit.
	xor	bh,2			; Turn networking bit off.
;
m.init.os.nonet:
	mov	cx,0022h		; Start with CP/M-86 BDOS version 2.2
	or	ax,cmdname		; CP/M has cmdname capability
	test	bh,bh			; CP/M-86 ?
	jz	m.init.os.found		; Yes.
	xor	ax,cmdname		; But MP/M and CCP/M do not.
	inc	cl			; No, try for MP/M-86.
	or	ax,multiuser+multitasking+multisector	; Yes, set MP/M-86 capabilities.
	cmp	bh,1			; MP/M-86 ?
	je	m.init.os.found		; Yes.
	inc	cl			; Try for CCP/M-86 (CX = 24h).
	xor	ax,multiuser		; CCP/M-86 lacks multiuser of MP/M.
	cmp	bh,14h			; CCP/M-86 ?
	je	m.init.os.found		; Yes.
	sub	cx,cx			; Unrecognized operating system.
;	jmps	m.init.os.found		; Join common code.
;
m.init.os.found:
	mov	_os_version,cl		; Store O/S version byte.
	mov	_os_ability,ax		; Store O/S ability word.
	ret				; Return.
;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; *									      *
; *                                  D A T A				      *
; *									      *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
DGROUP		GROUP	_OS_ABILITY,_OS_VERSION
;
_OS_ABILITY	dseg	common
		public	_os_ability
_os_ability	dw	0
;
_OS_VERSION	dseg	common
		public	_os_version
_os_version	db	0
;
	endif	;--------------------------------------------------------------
	end
«eof»