;MACROS for items that replace BIOS calls
;
;	Prolog Segname
;		start of code should be labeled
;		ENTRY:
;
;	Epilog	IntNo,Pointr,SegName
;		IntNo is interrupt number
;		Pointr is name of data area DD
;
;	Finish	SegName,StackSize
;  the variable  zzarg gets set to the first word (two chars) entered
;	on the command line
;
;	Finish has first label of CONFIG:
;	if HIMSG exists it is printed (put after Epilog)
;	eg	jmp CONFIG
;	   HIMSG db 'hello$'


; Prolog SegName
;	This pushes a bit and then runs to the rest
;	name the segment here

Prolog	MACRO	SegName
pBase	equ	00h	;pBase of memory (seg)
zbufr	equ	5Dh



DGROUP	GROUP	SegName,ZzUseStk
 
SegName	Segment	para

Moveit	PROC	FAR
   ASSUME	CS:SegName

;Set up the stack so a RET instruction
;	will jump to the
;	beginning of program segment
	push	ds	;Prog segment
	xor	ax,ax
	push	ax	;Offset

	jmp	DoTheRest

	db	'1982 MSZachmann'
MoveIt	endp
	ENDM
;	Epliog	IntNo,Pointr
;
;  This does the work of checking 
; that no other one has been loaded.
; Just exits if other loaded. IntNo
; is the interrupt number
; Pointer is a pointer to where the 
; old address should be stored.


Epilog	MACRO	IntNo,Pointr,SegName
EndEntry label	near

;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;
;	Temporary stuff
;
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


Initial	proc	near
DoTheRest	LABEL	NEAR

;Check to see if already loaded.
; if so, exit
;
	mov	BX,zbufr
	mov	AX,[BX]
	mov	CS:zzarg,AX
	push	DS
	mov	AX,pBase
	mov	DS,AX
	mov	BX,4*IntNo
	LES	SI,dword ptr [BX]
;now have start address of code
	mov	SI,offset ENTRY	;start here
	mov	DI,SI
	mov	AX,CS
	mov	DS,AX	; all set for compare
	CLD	;forward
	mov	CX,010	;should suffice
	REPE	CMPSW
	pop	DS
; now set status byte to 0FFFh
	mov	AX,0FFFFh
	push	AX
	jne	short	Nxt1
	jmp	Config


;Modify the INT 20H instruction at DS:1
;	Make it an INT 27h
Nxt1:	mov	BX,1
	mov	BYTE PTR [BX],27h

;relocate down a page using CS:->DS:
;
	mov	AX,DS
	mov	ES,AX	;set ES to page lower
	mov	AX,CS
	mov	DS,AX	;set DS to here
	mov	SI,offset ENTRY
	mov	DI,SI	;both same
	mov	CX,offset EndEntry-offset ENTRY
	shr	CX,1	;div by 2 for wds
	inc	CX	;for luck
lz1:	rep movsw
	and	CX,CX
	jnz	lz1

;Set DS:BX to point to int vector IntNo
;		(Pointr i/o )
	MOV	AX,pBase
	MOV	DS,AX
	MOV	BX,4*IntNo


	push	ES	;save new page

;Set ES:DI to old vector 10h
	LES	DI,DWORD PTR [BX]

;Reset the vector to Entry point
	MOV	WORD PTR [BX],offset ENTRY
	pop	CX	;new page number
	MOV	WORD PTR [BX+2],CX

;Now put the old vector address
;	into the call pointer at
;	DS:Pointr
   ASSUME   DS:&SegName
;actually DS is SegName-100h
	MOV	DS,CX
	MOV	Pointr,DI
	MOV	Pointr+2,ES
;set status to NEW 
	pop	AX	;get status back
	xor	AX,AX
	push	AX	;for later
Initial	endp

	ENDM

;	Finish
; exits
;	takes segment name and stack size

Finish	MACRO	SegName,SSizez


;Set up DX to the program size, note
;	that CS is 100h larger than
;	program prefix segment
; ! This is the lazy way, and
;	assumes PC-DOS stays consistent.

Nconfig	proc	far
CONFIG	label	near
	mov	AX,CS
	mov	DS,AX	;for print screen
	IFDEF	HIMSG
	mov	AH,9	;print string
	mov	DX,offset CLearstr
	int	21h	;DOS
	mov	DX,offset HIMSG
	int	21h
	ENDIF

	pop	AX	;get status
	and	AX,AX	;if zero then new
	jz	CONF3
	mov	DX,offset AlThere
	mov	AH,9
	int	21h	;print
CONF3:	MOV	DX,offset endENTRY
	RET	;Exit from the system
		;By doing an INT 27h
ALThere	db	'*** This program was already loaded. ***',13,10,'$'
zzarg	dw	?	;will contain first word at 80h
Clearstr db	13
	db	27 dup(10)
	db	'$'
Nconfig	endp



SegName	ends

; ensure that stack gets loaded highest in memory
; by naming it large (ZZ...)

ZzUSERST	segment	STACK
	dw	SSizez dup (?)
ZzUSERST	ENDS


	ENDM

