COUNTR	EQU	72 ;16572 HZ

TCADRC	EQU	43H
TCADRD	EQU	40H

TCMODE	EQU	34H
TC2MODE	EQU	0B8H

PPIADR	EQU	61H
NORMPPI	EQU	48H

;-------------------------------------------

STK	SEGMENT	STACK
	DW	128 DUP (0)
STK	ENDS

;-------------------------------------------

CODE	SEGMENT	PARA
	ASSUME	CS:CODE,DS:CODE,SS:STK
	ASSUME	ES:NOTHING

;-------------------------------------------

FILELEN	DW	0
HANDLE	DW	0
MSG2	DB	'Disk error',0DH,0AH,24H

;-------------------------------------------

START:

	CALL	PARSESGL

;set DS and ES

	PUSH	CS
	POP	DS
	PUSH	CS
	POP	ES

;open the file

	MOV	DX,OFFSET PARM
	MOV	AX,3D00H
	INT	21H
	JNC	L1
	JMP	DSKERR
L1:	MOV	HANDLE,AX

;read the file

	PUSH	DS
	MOV	BX,HANDLE
	MOV	AX,HIMEM
	MOV	DS,AX
	ASSUME	DS:NOTHING
	MOV	DX,0
	MOV	CX,0FFFFH
	MOV	AH,3FH
	INT	21H
	POP	DS
	ASSUME	DS:CODE
	JNC	L2
	JMP	DSKERR
L2:	MOV	FILELEN,AX

;close the file

	MOV	BX,HANDLE
	MOV	AH,3EH
	INT	21H

;get vector of timer current timer interrupt

	MOV	AX,3508H
	INT	21H
	MOV	WORD PTR OLDTMRINT,BX
	MOV	WORD PTR OLDTMRINT+2,ES

;mask timer interrupt

	IN	AL,21H
	OR	AL,01H
	OUT	21H,AL

;plug in the local timer interrupt routine

	MOV	DX,OFFSET TIMERINT
	MOV	AX,2508H
	INT	21H

;rev up timer

	MOV	AL,TCMODE
	OUT	TCADRC,AL
	MOV	AX,COUNTR
	OUT	TCADRD,AL
	MOV	AL,AH
	OUT	TCADRD,AL

;set DS

	ASSUME	DS:NOTHING
	MOV	AX,HIMEM
	MOV	DS,AX

;initialize registers

	MOV	BP,0
	MOV	BX,0
	MOV	CH,[BX]
	MOV	AH,0
	MOV	DX,PPIADR

;unmask timer interrupt

	IN	AL,21H
	AND	AL,0FEH
	OUT	21H,AL
	STI

;test for done

TFD:
	OR	BP,BP
	JE	TFD

;mask timer interrupt

	CLI
	IN	AL,21H
	OR	AL,01H
	OUT	21H,AL
	STI

;fix DS

	MOV	AX,CS
	MOV	DS,AX
	ASSUME	DS:CODE

;fix timer

	MOV	AL,TCMODE
	OUT	TCADRC,AL
	MOV	AL,0
	OUT	TCADRD,AL
	OUT	TCADRD,AL

;restore original timer interrupt vector

	PUSH	DS
	LDS	DX,CS:OLDTMRINT
	MOV	AX,2508H
	INT	21H
	POP	DS

;unmask timer interrupt

	IN	AL,21H
	AND	AL,0FEH
	OUT	21H,AL

;figure out how long the system 18.2 Hz
; timer has been off

	MOV	AX,COUNTR
	SHL	AX,1
	SHL	AX,1
	SHL	AX,1
	MOV	CX,FILELEN
	MUL	CX

;adjust the BIOS time of day to catch up

	PUSH	ES
	MOV	AX,40H
	MOV	ES,AX
	MOV	BX,6CH
	CLI
	ADD	ES:[BX],DX
	ADC	WORD PTR ES:[BX+2],0
	CMP	WORD PTR ES:[BX+2],18H
	JB	BIOSFIXED
	JA	WRAP
	CMP	WORD PTR ES:[BX],0B0H
	JB	BIOSFIXED
WRAP:	SUB	WORD PTR ES:[BX],0B0H
	SBB	WORD PTR ES:[BX+2],18H
BIOSFIXED: STI
	POP	ES

;exit

	MOV	AX,4C00H
	INT	21H

;disk error message

DSKERR:
	MOV	AX,CS
	MOV	DS,AX
	MOV	DX,OFFSET MSG2
	MOV	AH,9
	INT	21H
	MOV	AX,4C01H
	INT	21H

;-------------------------------------------

;timer interrupt routine

	ASSUME	DS:NOTHING,ES:NOTHING
	ASSUME	SS:NOTHING

	EVEN

OLDTMRINT DD	0

TIMERINT PROC	FAR

	OR	BP,BP
	JNZ	TMRINT1

	SUB	AL,AL
	RCL	CH,1
	RCL	AL,1
	RCL	AL,1
	OR	AL,NORMPPI
	OUT	DX,AL

	INC	AH
	CMP	AH,8
	JNE	TMRINT1
	SUB	AH,AH

	INC	BX
	MOV	CH,[BX]
	CMP	BX,FILELEN
	JNZ	TMRINT1
	INC	BP

TMRINT1:
	MOV	AL,20H
	OUT	20H,AL
	IRET

TIMERINT ENDP

;-------------------------------------------

PARM	DB	128 DUP (0)

SPECERRMSG	DB	'File specification'
	DB	' error',0DH,0AH,24H

;it is assumed that DS and ES both point
; to the PSP.

PARSESGL	PROC

	CLD
	MOV	DI,80H
	MOV	CL,[DI]
	SUB	CH,CH
	INC	DI

	CMP	CX,1
	JBE	PARSS4

;find first non-blank character

	MOV	AL,20H
	REPE	SCASB
	JNE	PARSS2
PARSS4:	PUSH	CS
	POP	DS
	MOV	DX,OFFSET SPECERRMSG
	MOV	AH,9
	INT	21H
	MOV	AX,4C01H
	INT	21H

;find next blank character or end

PARSS2:
	DEC	DI
	INC	CX
	MOV	BX,DI
	REPNE	SCASB

;save parameter

	JCXZ	PARSS3
	DEC	DI
PARSS3:	PUSH	CX
	PUSH	DI
	PUSH	ES
	PUSH	CS
	POP	ES
	MOV	CX,DI
	SUB	CX,BX
	MOV	SI,BX
	MOV	DI,OFFSET PARM
	REP	MOVSB
	POP	ES
	POP	DI
	POP	CX

	RET

PARSESGL	ENDP

;-------------------------------------------

CODE	ENDS

;-------------------------------------------

HIMEM	SEGMENT	PARA
HIMEM	ENDS

	END	START
