h31197
s 00092/00104/00361
d D 1.2 83/03/18 19:34:25 bog 2 1
c V1.1 Avoid interrupt in stack swap
e
s 00465/00000/00000
d D 1.1 83/03/15 21:23:44 tes 1 0
c date and time created 83/03/15 21:23:44 by tes
e
u
4
U
t
T
I 1
D 2
	title	'Main program for medium res color IBM PC device driver'
E 2
I 2
	title	'Main for Medium Resolution Color IBM PC device driver'

CSA1	Equ	0		; -2 for Control Systems Artist 1
E 2
 
;	this is the starting point for all C programs
;	Upon entry, ds:dx points to a parameter block of 5 double word
;	pointers to the parameters for the device driver.
 
	dseg
 
;	the following data structure is created and initialised by the linker
;	it specifies the size and address of uninitialised global storage
;	it is available to various routines as "_sysuglo"
 
sysuglo	rw	0	;control structure generated by the linker
gfirst	rw	1	;address of first uninitialised global byte
glen	rw	1	;length of the uninitialised global region
 
;	the following data structure is known as "_sysvals" by various
;	parts of the system, including alloc and $entry?
 
	org	0
 
sysvals	rw	0	;a control data structure for a C program
sreserv	dw	80h	;minumum stack space above heap before HEAP ERROR
htop	dw	80h	;top of heap (includes reserv) for HEAP ERROR check
D 2
savess	dw	0	;place to save entry reg ss during execution
savesp	dw	0	;place to save entry reg sp during execution
E 2
ctloff	rw	1	;place to save seg offset of control array
ctlseg	rw	1	;place to save seg base of control array
inioff	rw	1	;place to save seg offset of intin array
iniseg	rw	1	;place to save seg base of intin array
ptioff	rw	1	;place to save seg offset of ptsin array
ptiseg	rw	1	;place to save seg base of ptsin array
inooff	rw	1	;place to save seg offset of intout array
inoseg	rw	1	;place to save seg base of intout array
ptooff	rw	1	;place to save seg offset of ptsout array
ptoseg	rw	1	;place to save seg base of ptsout array
D 2
hem	db	13,10,'NO CORE$'
E 2
I 2
hem	db	13,10,'No memory$'
E 2
 
;	the following symbol may be used to determine the o/s type
 
under_systype	dw	0	;for cp/m-86
 
;	the following symbol controls trace-back at _exit time
 
under_exittbc	db	0	;0=none, 1=error, 0xff=always
		db	0,0,0,0ah,0dh,'$'	;data area for above
 
DEFCGBL	equ	0c1h		;define a global in code segment
DEFDGBL equ	0c2h		;define a global in data segment
RELCGBL	equ	0c3h		;relative address of global in code
ABSCGBL equ	0c4h		;absolute reference to global in code
 
	cseg
 
;	the following symbols are used local to main
mlocal		rw	0	;local data structure for main
first_time	dw	0	;first time flag - used for initialization

;	$main	entry point for c programs

dollar_main:
D 2
	push	bp			;save caller's frame
	pushf				;save flags (psw)
	push	es			;save caller's es
	push	ds			;save caller's ds
	push	ds			;save ptr to parameter block
	push	dx
E 2
I 2
	push	bp		;save caller's frame
	pushf			;save flags (psw)
	pop	Bp		;  in Bp
	push	Bp		;back to stack
	push	es		;save caller's es
	push	ds		;save caller's ds
	Mov	Si,Dx		;Si <- offset to caller's param block
	Push	Si		; Save it
	Mov	Bx,Offset SysVals; Base of control block structure
glo_adj_1	Equ	$-2
E 2
 
D 2
;	get base page of driver on first call, so the data segment
;       can be set up appropriately for future calls
E 2
I 2
; If first time through, find local DSeg and initialize global storage region
	Mov	Dx,Cs:First_Time; Get segbase of DSeg; 0 if first time
glo_adj_31	Equ	$-2
	Mov	Es,Dx		; Point Es to local DSeg if not first time
E 2

D 2
glo_adj_31	equ 	$+3
	cmp	first_time,0	
	jne	not_first_time
E 2
I 2
	Or	Dx,Dx		; First time?
	Jnz	Not_First_Time	; Jump if not first time
E 2

D 2
	mov	cx,0673h		;call gdos with return ptr opcode
	int	224			;si = segment base of base page table
	mov	si,es:5[bx]
	jmp	set_up_stack		;set up stack
E 2
I 2
	Push	Bx		; Save offset of SysVals
	And	Ch,0f0h		; Preserve layer number
	Or	Ch,006h		; Return layer pointer function
	Int	224		; Gdos call
	Mov	Dx,Es:5[Bx]	; Get base page segbase
	Mov	Es,Dx		;  also into Es
	Pop	Bx		; Restore offset of SysVals
E 2

D 2
not_first_time:
	mov	si,first_time		;set ds saved from gdos call
glo_adj_32	equ	$-2
E 2
I 2
	Mov	Cs:First_Time,Dx; No longer first time through
glo_adj_34	Equ	$-2
	Mov	Di,Es:GFirst	; Start of static uninitialized area
glo_fix_1	Equ	$-2
	Mov	Cx,Es:GLen	; Length of uninit static
glo_fix_2	Equ	$-2
	Add	Es:HTop[Bx],Di	; Calculate heap top for alloc
	Add	Es:HTop[Bx],Cx
E 2

D 2
set_up_stack:
	mov	ds,si			;set up local data segment
	pop	dx			;restore ptr to parameter block es:dx
	pop	es
E 2
I 2
	Sub	Al,Al		; Need to clear uninit area
	Cld			; Work up in address
    Rep	Stosb			; Clear uninitialized static globals
E 2

D 2
	mov	bx,offset sysvals	;get control block address
glo_adj_1	equ	$-2		;for linker
	mov	savess[bx],ss		;save the stack seg
	mov	savesp[bx],sp		;and the stack pointer
E 2
I 2
; Switch to local stack from caller's stack
;  Ds:Si points to caller's parameter block
;  Es, Dx point to local DSeg
;  Bx holds offset of SysVals
;  Bp holds caller's Psw
;   Save caller's Ss:Sp
Not_First_Time:
	Mov	Cx,Ss		; Save caller's Ss:Sp in Cx, Di
	Mov	Di,Sp
E 2

D 2
	mov	ss,si			;set up stack segment
	mov	sp,.6			;data seg size from cpm
	and	sp,0fffeh		;force it even for alignment
	mov	bp,sp			;set bp too
E 2
I 2
	Mov	Ax,Es:(Word Ptr .6); Last offset in DSeg in base page
	Inc	Ax		; Make one beyond last offset
	And	Al,0feh		; Force it even
	Cli			; Disable interrupts
	Mov	Ss,Dx		; Driver stack in DSeg
	Mov	Sp,Ax		;  at end
	Push	Bp		; Re-enable interrupts
	Popf			;  if they were enabled
	Push	Cx		; Save caller's Ss:Sp
	Push	Di
	Mov	Bp,Sp		; Point Bp to caller's Ss:Sp
E 2

D 2
;	clear the uninitialized global storage region (first time only)
 
glo_adj_33	equ	$+3
	cmp	first_time,0
	jne	no_heap_init
E 2
I 2
; Move caller's parameter pointers to local DSeg so C can access them
	Mov	Di,Offset CtlOff; Di at base of global parameter area
glo_adj_17	Equ	$-2
;  Ds:Si points to caller's parameter block
;  Es:Di points to C parameter area in local DSeg
	Mov	Cx,10		; 10 words in 5 Dword Ptrs
	Cld			; Work up in address
   Rep	Movsw			; Move parameters to local DSeg
E 2

D 2
	mov	first_time,si		;first time so save local ds
glo_adj_34	equ	$-2
E 2
I 2
; Call the driver
	Mov	Ds,Dx		; Segbase of local DSeg
;  Ds points to local DSeg
;  Cs points to local CSeg (set by far call which got us here)
E 2

D 2
	cld				;to go up
	mov	di,gfirst		;start of static uninitialised area
glo_fix_1	equ	$-2
	mov	cx,glen			;# of bytes to clear
glo_fix_2	equ	$-2
	add	htop[bx],di		;calc heap top for alloc
	add	htop[bx],cx
	xor	ax,ax			;zero ax
	rep	stos	al		;clear the area
 
;	set up parameters for device driver in c
;	on entry es:dx points to parameter block of addresses

no_heap_init:

	push	ds			;save local ds
	mov	si,dx			;get ptr to parameter block 
	push	es
	pop	ds			;ds:si = ptr to parameter block
	pop	es			;get seg base of global parameter area
					;  es = local ds
	mov	di,offset ctloff	;get offset of global parameter area
glo_adj_17	equ	$-2		;es:di = ptr to global parameter area
	mov	cx,10			;parameter block is 5 dword pointers
	cld				;set direction flag for autoincrement
rep	movsw				;move parm addresses into global area

	push	es
	pop	ds			;es = ds for c

;	call the driver routine 
 
E 2
call_driver:
umain	equ	$+1
	call	$+3			;enter c system at driver

;	remove parameter addresses from stack - c does not do this itself

	mov	sp,bp			;set stack back to initial state -
					;remove parameters 

D 2
	jmp	tb_none			;skip traceback & error checking
;	jmps	under_exit
E 2
I 2
	jmps	tb_none			;skip traceback & error checking
E 2
 
D 2
;	a heap error has occured
 
heap_error:
	mov	cl,9
	mov	dx,offset hem		;address of message
hem_adj equ	$-2			;for relocation by linker
	int	224			;say buy more core
	mov	ax,8000h		;set error flag
;	jmps	under_exit		;go to the exit mechanism
 
 
E 2
I 2
; a heap error has occurred
Heap_Error:
	Mov	Cl,9		; Bdos "Print String" function
	Mov	Dx,Offset Hem	; Offset of "NO MEM" message
hem_adj	Equ	$-2
	Int	224
	Mov	Ax,08000h	; Set error flag

E 2
;	_exit	abort exit point for c programs
 
under_exit:
	mov	bl,under_exittbc	;get the trace back control byte
tbc_adj_1	equ	$-2
	or	bl,bl
	jz	tb_none		;traceback is off
	js	tb_go		;do it
	or	ax,ax		;any error returned
	jz	tb_none		;nope
tb_go:
	push	ax		;save the exit value
tb_loop:
	mov	dx,2[bp]	;get a call address
	mov	si,4		;hex digits per word
	lea	bx,under_exittbc	;get the data address
tbc_adj_2	equ	$-2
tb_digit:
	mov	al,dl		;get a digit
	mov	cl,4
	shr	dx,cl		;strip the digit
	and	al,0fh		;keep low nibble
	add	al,090h
	daa
	adc	al,040h
	daa
	dec	si		;count the digit
	mov	[bx+si],al	;store the digit
	jnz	tb_digit
	mov	dx,bx
	mov	cl,9
	int	0e0h
	cmp	[bp],bp
	jbe	tb_done
	mov	bp,[bp]		;up the stack
	jmps	tb_loop
tb_done:
	pop	ax		;restore ax
tb_none:
D 2
	mov	ss,savess	;restore reg ss
glo_adj_2	equ	$-2
	mov	sp,savesp	;restore the stack
glo_adj_3	equ	$-2
E 2
I 2
	Pop	Di		; Get back caller's Sp
	Pop	Cx		;  & Ss
	cli			;disable interrupts (restored below)
	mov	ss,Cx		;restore reg ss
	mov	sp,Di		;restore the stack

	pop	dx		;restore caller's dx
E 2
	pop	ds		;restore caller's ds
	pop	es		;restore caller's es
	popf			;restore flags (psw)
	pop	bp		;restore caller's stack frame
	retf				;and a far return
 
;	set up on entry to a function
 
dollar_entry0:
	pop	si		;get address we came from
	xor	ax,ax		;no locals in this procedure
	jmps	entry1
dollar_entry1:
	pop	si		;get address we came from
	cld
	db	2eh		;seg override prefix to cs:
	lods	al		;get offset
	mov	ah,0		;as a word value
entry1:
	push	bp		;save frame pointer
	mov	bp,sp		;get new frame pointer
	sub	sp,ax		;adjust stack
	cmp	sp,htop		;how is heap space
glo_adj_4	equ	$-2
	jbe	heap_error	;crash
	jmp	si		;go to program
dollar_entry2:
	pop	si		;get address we came from
	cld
	db	2eh		;seg override prefix to cs:
	lods	ax		;get the offset
	jmps	entry1
 
;
;	These utility routines are used to get and put data from
;	the device driver parameter lists.  They use the 32 bit 
;	pointers that were stored upon driver entry in the system
;	area '_sysvals'.
;
;
;	n = getctl (i) - get word from control array
;	   i = index into control array (0 based)
;	   n = value of word in control array
;
getctl:
	push	bp		; save base pointer
	mov	bp,sp		; set up pointer into stack
	push	es		; save registers
	push	si
	
	les	si,dword ptr ctloff	; get seg base & offset of contrl array
glo_adj_11	equ	$-2
	mov	bx,4[bp]	; get index of element to access
	shl	bx,1		; turn word index into bytes
D 2
	mov	ax,es:(word ptr 0)[si+bx]
E 2
I 2
	mov	ax,es:(word ptr CSA1)[si+bx]
E 2

	pop	si		; restore registers
	pop	es
	pop	bp
	ret

;
;	n = getini (i) - get word from intin array
;	   i = index into intin	 array (0 based)
;	   n = value of word in intin array
;
getini:
	push	bp		; save base pointer
	mov	bp,sp		; set up pointer into stack
	push	es		; save registers
	push	si
	
	les	si,dword ptr inioff	; get seg base & offset of intin array
glo_adj_12	equ	$-2
	mov	bx,4[bp]	; get index of element to access
	shl	bx,1		; turn word index into bytes
D 2
	mov	ax,es:(word ptr 0)[si+bx]
E 2
I 2
	mov	ax,es:(word ptr CSA1)[si+bx]
E 2

	pop	si		; restore registers
	pop	es
	pop	bp
	ret

;
;	n = getpti (i) - get word from ptsin array
;	   i = index into ptsin array (0 based)
;	   n = value of word in ptsin array
;
getpti:
	push	bp		; save base pointer
	mov	bp,sp		; set up pointer into stack
	push	es		; save registers
	push	si
	
	les	si,dword ptr ptioff	; get seg base & offset of ptsin array
glo_adj_13	equ	$-2
	mov	bx,4[bp]	; get index of element to access
	shl	bx,1		; turn word index into bytes
D 2
	mov	ax,es:(word ptr 0)[si+bx]
E 2
I 2
	mov	ax,es:(word ptr CSA1)[si+bx]
E 2

	pop	si		; restore registers
	pop	es
	pop	bp
	ret

;
;	putctl (i, n) - put word into control array
;	   i = index into control array (0 based)
;	   n = value of word in control array
;
putctl:
	push	bp		; save base pointer
	mov	bp,sp		; set up pointer into stack
	push	es		; save registers
	push	si
	
	
	les	si,dword ptr ctloff	; get seg base & offset of contrl array
glo_adj_14	equ	$-2
	mov	bx,4[bp]	; get index of element to access
	shl	bx,1		; turn word index into bytes
	mov	ax,6[bp]	; get new value
D 2
	mov	es:(word ptr 0)[si+bx],ax
E 2
I 2
	mov	es:(word ptr CSA1)[si+bx],ax
E 2

	pop	si		; restore registers
	pop	es
	pop	bp
	ret

;
;	putino (i, n) - put word into intout array
;	   i = index into intout array (0 based)
;	   n = value of word in intout array
;
putino:
	push	bp		; save base pointer
	mov	bp,sp		; set up pointer into stack
	push	es		; save registers
	push	si
	
	les	si,dword ptr inooff	; get seg base & offset of intout array
glo_adj_15	equ	$-2
	mov	bx,4[bp]	; get index of element to access
	shl	bx,1		; turn word index into bytes
	mov	ax,6[bp]	; get new value
D 2
	mov	es:(word ptr 0)[si+bx],ax
E 2
I 2
	mov	es:(word ptr CSA1)[si+bx],ax
E 2

	pop	si		; restore registers
	pop	es
	pop	bp
	ret

;
;	putpto (i, n) - put word into ptsout array
;	   i = index into ptsout array (0 based)
;	   n = value of word in ptsout array
;
putpto:
	push	bp		; save base pointer
	mov	bp,sp		; set up pointer into stack
	push	es		; save registers
	push	si
	
	les	si,dword ptr ptooff	; get seg base & offset of ptsout array
glo_adj_16	equ	$-2
	mov	bx,4[bp]	; get index of element to access
	shl	bx,1		; turn word index into bytes
	mov	ax,6[bp]	; get new value
D 2
	mov	es:(word ptr 0)[si+bx],ax
E 2
I 2
	mov	es:(word ptr CSA1)[si+bx],ax
E 2

	pop	si		; restore registers
	pop	es
	pop	bp
	ret

;	define the addresses to relocate in the above code
 
	eseg
 
	dw	dollar_main
	db	DEFCGBL,'$main',0
	dw	under_exit
	db	DEFCGBL,'_exit',0
	dw	dollar_entry0
	db	DEFCGBL,'$entry0',0
	dw	dollar_entry1
	db	DEFCGBL,'$entry1',0
	dw	dollar_entry2
	db	DEFCGBL,'$entry2',0
	dw	umain    		; name of driver
	db	RELCGBL,'ddibmc',0
	dw	sysvals
	db	DEFDGBL,'_sysvals',0
	dw	under_systype
	db	DEFDGBL,'_systype',0
	dw	under_exittbc
	db	DEFDGBL,'_exittbc',0
 
	dw	tbc_adj_1
	db	ABSCGBL,'_sysvals',0	;gives correct final address
	dw	tbc_adj_2
	db	ABSCGBL,'_sysvals',0
 
	dw	hem_adj
	db	ABSCGBL,'_sysvals',0
	dw	glo_adj_1
	db	ABSCGBL,'_sysvals',0
D 2
	dw	glo_adj_2
	db	ABSCGBL,'_sysvals',0
	dw	glo_adj_3
	db	ABSCGBL,'_sysvals',0
E 2
	dw	glo_adj_4
	db	ABSCGBL,'_sysvals',0
	dw	glo_adj_11
	db	ABSCGBL,'_sysvals',0
	dw	glo_adj_12
	db	ABSCGBL,'_sysvals',0
	dw	glo_adj_13
	db	ABSCGBL,'_sysvals',0
	dw	glo_adj_14
	db	ABSCGBL,'_sysvals',0
	dw	glo_adj_15
	db	ABSCGBL,'_sysvals',0
	dw	glo_adj_16
	db	ABSCGBL,'_sysvals',0
	dw	glo_adj_17
	db	ABSCGBL,'_sysvals',0
	dw	glo_fix_1
	db	ABSCGBL,'_sysuglo',0
	dw	glo_fix_2
	db	ABSCGBL,'_sysuglo',0

	dw	getctl
	db	DEFCGBL,'getctl',0
	dw	getini
	db	DEFCGBL,'getini',0
	dw	getpti
	db	DEFCGBL,'getpti',0
	dw	putctl
	db	DEFCGBL,'putctl',0
	dw	putino
	db	DEFCGBL,'putino',0
	dw	putpto
	db	DEFCGBL,'putpto',0

	dw	mlocal
	db	DEFCGBL,'_mlocal',0
	dw	glo_adj_31
D 2
	db	ABSCGBL,'_mlocal',0
	dw	glo_adj_32
	db	ABSCGBL,'_mlocal',0
	dw	glo_adj_33
E 2
	db	ABSCGBL,'_mlocal',0
	dw	glo_adj_34
	db	ABSCGBL,'_mlocal',0

	dw	0,0
 
	end
E 1
