PAGE 118,121
TITLE TEST4 ---- 06/10/85  POST AND BIOS UTILITY ROUTINES
.286C
.LIST
CODE	SEGMENT BYTE PUBLIC

	PUBLIC	BEEP
	PUBLIC	BLINK_INT
	PUBLIC	CMOS_READ
	PUBLIC	CMOS_WRITE
	PUBLIC	CONFTG_BAD
	PUBLIC	D11
	PUBLIC	DDS
	PUBLIC	DUMMY_RETURN_1
	PUBLIC	ERR_BEEP
	PUBLIC	E_MSG
	PUBLIC	INT_287
	PUBLIC	KBD_RESET
	PUBLIC	POST4
	PUBLIC	PROT_PRT_HEX
	PUBLIC	PROC_SHUTDOWN
	PUBLIC	PRT_HEX
	PUBLIC	PRT_SEG
	PUBLIC	P_MSG
	PUBLIC	RE_DIRECT
	PUBLIC	ROM_CHECK
	PUBLIC	ROM_CHECKSUM
	PUBLIC	SET_TOD
	PUBLIC	WAITF
	PUBLIC	XPC_BYTE

	EXTRN	E163:NEAR
	EXTRN	OBF_42:NEAR
	EXTRN	ROM_ERR:NEAR
	EXTRN 	XMIT_8042:NEAR

	ASSUME	CS:CODE,DS:DATA

POST4:
;--- CMOS_READ -----------------------------------------------------------------
;		READ BYTE FROM CMOS_SYSTEM CLOCK CONFIGURATION TABLE	:
;				:
; INPUT: (AL)=	CMOS_TABLE ADDRESS TO BE READ	:
;		BIT    7 = 0 FOR NMI ENABLED AND 1 FOR NMI DISABLED ON EXIT	:
;		BITS 6-0 = ADDRESS OF TABLE LOCATION TO READ	:
;				:
; OUTPUT: (AL)	VALUE AT LOCATION (AL) MOVED INTO (AL). IF BIT 7 OF (AL) WAS	:
;		ON THEN NMI LEFT DISABLED, DURING THE CMOS READ BOTH NMI AND	: 
;		NORMAL INTERRUPTS ARE DISABLED TO PROTECT CMOS DATA INTEGRITY. :
;		THE CMOS ADDRESS REGISTER IS POINTED TO A DEFAULT VALUE AND	:
;		THE INTERRUPT FLAG RESTORED TO THE ENTRY STATE ON RETURN.	:
;		ONLY THE (AL) REGISTER AND THE NMI STATE IS CHANGED.	:
;-------------------------------------------------------------------------------

CMOS_READ	PROC	NEAR	; READ LOCATION (AL) INTO (AL)
	PUSHF		; SAVE INTERRUPT ENABLE STATUS AND FLAGS
	ROL	AL,1	; MOVE NMI BIT TO LOW POSITION
	STC		; FORCE NMI BIT ON IN CARRY FLAG
	RCR	AL,1	; HIGH BIT ON TO DISABLE NMI - OLD IN CY
	CLI		; DISABLE INTERRUPTS
	OUT	CMOS_PORT,AL	; ADDRESS LOCATION AND DISABLE NMI
	NOP		; I/O DELAY
	IN	AL,CMOS_DATA	; READ THE REQUESTED CMOS LOCATION
	PUSH	AX	; SAVE (AH) REGISTER VALUE AND CMOS BYTE
	MOV	AL,CMOS_REG_D*2	; GET ADDRESS OF DEFAULT LOCATION
	RCR	AL,1	; PUT ORIGINAL NMI MASK BIT INTO ADDRESS
	OUT	CMOS_PORT,AL	; SET DEFAULT TO READ ONLY REGISTER
	POP	AX	; RESTORE (AH) AND (AL), CMOS BYTE
	PUSH	CS	; *PLACE CODE SEGMENT IN STACK AND
	CALL	CMOS_POPF	; *HANDLE POPF FOR B- LEVEL 80286
	RET		; RETURN WITH FLAGS RESTORED

CMOS_READ	ENDP

CMOS_POPF	PROC	NEAR	; POPF FOR LEVEL B- PARTS
	IRET		; RETURN FAR AND RESTORE FLAGS
CMOS_POPF	ENDP

;--- CMOS_WRITE	----------------------------------------------------------------
;	WRITE BYTE TO CMOS SYSTEM CLOCK CONFIGURATION TABLE	:
;				:
; INPUT: (AL)=	CMOS TABLE ADDRESS TO BE WRITTEN TO	:
;		BIT    7 = 0 FOR NMI ENABLED AND 1 FOR NMI DISABLED ON EXIT	:
;		BITS 6-0 = ADDRESS OF TABLE LOCATION TO WRITE	:
;	(AH)=	NEW VALUE TO BE PLACED IN THE ADDRESSED TABLE LOCATION	:
;				:
; OUTPUT:	VALUE IN (AH) PLACED IN LOCATION (AL) WITH NMI LEFT DISABLED	:
;		IF BIT 7 OF (AL) IS ON, DURING THE CMOS UPDATE BOTH NMI AND	:
;		NORMAL INTERRUPTS ARE DISABLED TO PROTECT CMOS DATA INTEGRITY.	:
;		THE CMOS ADDRESS REGISTER IS POINTED TO A DEFAULT VALUE AND	:
;		THE INTERRUPT FLAG RESTORED TO THE ENTRY STATE ON RETURN.	:
;		ONLY THE CMOS LOCATION AND THE NMI STATE IS CHANGED.	:
;-------------------------------------------------------------------------------

CMOS_WRITE	PROC	NEAR	; WRITE (AH) TO LOCATION (AL)
	PUSHF		; SAVE INTERRUPT ENABLE STATUS AND FLAGS
	PUSH	AX	; SAVE WORK REGISTER VALUES
	ROL	AL,1	; MOVE NMI BIT TO LOW POSITION
	STC		; FORCE NMI BIT ON IN CARRY FLAG
	RCR	AL,1	; HIGH BIT ON TO DISABLE NMI - OLD IN CY
	CLI		; DISABLE INTERRUPTS
	OUT	CMOS_PORT,AL	; ADDRESS LOCATION AND DISABLE NMI
	MOV	AL,AH	; GET THE DATA BYTE TO WRITE
	OUT	CMOS_DATA,AL	; PLACE IN REQUESTED CMOS LOCATION
	MOV	AL,CMOS_REG_D*2	; GET ADDRESS OF DEFAULT LOCATION
	RCR	AL,1	; PUT ORIGINAL NMI MASK BIT INTO ADDRESS
	OUT	CMOS_PORT,AL	; SET DEFAULT TO READ ONLY REGISTER
	POP	AX	; RESTORE WORK REGISTERS
	PUSH	CS	; PLACE CODE SEGMENT IN STACK AND
	CALL	CMOS_POPF	; HANDLE POPF FOR B- LEVEL 80286
	RET
CMOS_WRITE	ENDP

DDS	PROC	NEAR	; 	  LOAD (DS) TO DATA AREA
	MOV	DS,CS:DDSDATA	; PUT SEGMENT VALUE OF DATA AREA INTO DS
	RET		; RETURN TO USER WITH (DS)= DATA

DDSDATA	DW	DATA	; SEGMENT SELECTOR VALUE FOR DATA AREA

DDS 	ENDP

;--- E_MSG -- P MSG ------------------------------------------------------
;	THIS SUBROUTINE WILL PRINT A MESSAGE ON THE DISPLAY	:
;				:
; ENTRY REQUIREMENTS:		:
;	SI = OFFSET(ADDRESS) OF MESSAGE BUFFER	:
;	CX = MESSAGE BYTE COUNT		:
;	     MAXIMUM MESSAGE LENGTH IS 36 CHARACTERS	:
;	BP = BIT 0=E161/E162, BIT 1=CONFIG_BAD, 2-15= FIRST MSG OFFSET	:
;-------------------------------------------------------------------------

E_MSG	PROC	NEAR
	TEST	SP,03FFFH	; CHECK FOR NOT FIRST ERROR MESSAGE
	JNZ	E_MSG1	; SKIP IF NOT FIRST ERROR MESSAGE

	PUSH	SI	; SAVE MESSAGE POINTER
	AND	SI,03FFFH	; USE LOW 14 BITS OF MESSAGE OFFSET
	OR	BP,SI	;  AS FIRST ERROR MESSAGE FLAG
	POP	SI	; (BIT 0 = E161/E162, BIT 1 = BAD_CONFIG
E_MSG1:
	CALL	P_MSG	; PRINT MESSAGE
	PUSH	DS	; SAVE CALLERS (DS)
	CALL	DDS	; POINT TO POST/BIOS DATA SEGMENT
	TEST	BYTE PTR @EQUIP_FLAG,01H	; LOOP/HALT ON ERROR SWITCH ON ?
	JZ	MFG_HLT	; YES - THEN GO TO MANUFACTURING HALT

	POP	DS	; RESTORE CALLERS (DS)
	RET

MFG_HALT:		; MANUFACTURING LOOP MODE ERROR TRAP
	CLI		; DISABLE INTERRUPTS
	MOV	AL,@MFG_ERR_FLAG	; RECOVER ERROR INDICATOR
	OUT	MFG_PORT,AL	; SET INTO MANUFACTURING PORT
	HLT		; HALT SYSTEM
	JMP	MFG_HALT	; HOT NMI TRAP

E_MSG	ENDP

P_MSG	PROC	NEAR	; 	  DISPLAY STRING FROM (CS:)
	MOV	AL,CS:[SI]	; PUT CHARACTER IN (AL)
	INC	SI	; POINT TO NEXT CHARACTER
	PUSH	AX	; SAVE PRINT CHARACTER
	CALL	PRT_HEX	; CALL VIDEO_IO
	POP	AX	; RECOVER PRINT CHARACTER
	CMP	AL,LF	; WAS IT LINE FEED?
	JNE	P_MSG	; NO, KEEP PRINTING STRING
	RET

P_MSG	ENDP

;--- ERR BEEP -----------------------------------------------------------
;	THIS PROCEDURE WILL ISSUE LONG TONES (1-3/4 SECONDS) AND ONE OR	:
;	MORE SHORT TONES (9/32 SECOND) TO INDICATE A FAILURE ON THE	:
;	PLANAR BOARD, A BAD MEMORY MODULE, OR A PROBLEM WITH THE CRT.	:
; ENTRY PARAMETERS:		:
;	DH = NUMBER OF LONG TONES TO BEEP.	:
;	DL = NUMBER OF SHORT TONES TO BEEP.	:
;------------------------------------------------------------------------

ERR_BEEP		PROC	NEAR
	PUSHF		; SAVE FLAGS
	CLI		; DISABLE SYSTEM INTERRUPTS
	OR	DH,DH	; ANY LONG ONES TO BEEP
	JZ	G3	; NO, DO THE SHORT ONES
CL:			; 	  LONG BEEPS
	MOV	BL,112	; COUNTER FOR LONG BEEPS (1-3/4 SECONDS)
	MOV	CX,1280	; DIVISOR FOR 932 HZ
	CALL	BEEP	; DO THE BEEP
	MOV	CX,49715	; 2/3 SECOND DELAY AFTER LONG BEEP
	CALL	WAITF	; DELAY BETWEEN BEEPS
	DEC	DH	; ANY MORE LONG BEEPS TO DO
	JNZ	G1	; LOOP TILL DONE

	PUSH	DS	; SAVE DS REGISTER CONTENTS
	CALL	DDS
	CMP	@MFG_TST,01H	; MANUFACTURING TEST MODE?
	POP	DS	; RESTORE ORIGINAL CONTENTS OF (DS)
	JE	MFG_HALT	; YES - STOP BLINKING LED

G3:			; SHORT BEEPS
	MOV	BL,18	; COUNTER FOR A SHORT BEEP (9/32
	MOV	CX,1208	; DIVISOR FOR 987 HZ
	CALL	BEEP	; DO THE SOUND
	MOV	CX,33144	; 1/2 SECOND DELAY AFTER SHORT BEEP
	CALL	WAITF	; DELAY BETWEEN BEEPS
	DEC	DL	; DONE WITH SHORT BEEPS COUNT
	JNZ	G3	; LOOP TILL DONE
	
	MOV	CX,33144	; 1/2 SECOND DELAY AFTER LAST BEEP
	CALL	WAITF	; MAKE IT ONE SECOND DELAY BEFORE RETURN
	POPF		; RESTORE FLAGS TO ORIGINAL SETTINGS
	RET		; RETURN TO CALLER

ERR_BEEP		ENDP

;--- BEEP ----------------------------------------------------------------
;	ROUTINE TO SOUND THE BEEPER USING TIMER 2 FOR TONE	:
; ENTRY:				:
;	(BL) = DURATION COUNTER ( 1 FOR 1/64 SECOND )	:
;	(CX) = FREQUENCY DIVISOR (1193180/FREQUENCY) (1331 FOR 886 HZ)	:
; EXIT:				:
;	(AX),(BL),(CX) MODIFIED.		:
;-------------------------------------------------------------------------

BEEP	PROC	NEAR	;	SETUP TIMER 2
	PUSHF		; SAVE INTERRUPT STATUS
	CLI		; BLOCK INTERRUPTS DURING UPDATE
	MOV	AL,10110110B	; SELECT TIMER 2,LSB,MSB,BINARY
	OUT	TIMER+3,AL	; WRITE THE TIMER MODE REGISTER
	JMP	$+2	; I/O DELAY
	MOV	AL,CL	; DIVISOR FOR HZ (LOW)
	OUT	TIMER+2,AL	; WRITE TIMER 2 COUNT - LSB
	JMP	$+2	; I/O DELAY
	MOV	AL,CH	; DIVISOR FOR HZ (HIGH)
	OUT	TIMER+2,AL	; WRITE TIMER 2 COUNT - MSB
	IN	AL,PORT_B	; GET CURRENT SETTING OF PORT
	MCV	AH,AL	; SAVE THAT SETTING
	OR	AL,GATE2+SPK2	; GATE TIMER 2 AND TURN SPEAKER ON
	OUT	PORT_B,AL	; AND RESTORE INTERRUPT STATUS
	POPF
G7:			; 	  1/64 SECOND PER COUNT (BL)
	MOV	CX,1035	; DELAY COUNT FOR 1164 OF A SECOND
	CALL	WAITF	; GO TO BEEP DELAY 1/64 COUNT
	DEC	BL	; (BL) LENGTH COUNT EXPIRED?
	JNZ	G7	; NO - CONTINUE BEEPING SPEAKER

	PUSHF		; SAVE INTERRUPT STATUS
	CLI		; BLOCK INTERRUPTS DURING UPDATE
	IN	AL,PORT_B	; GET CURRENT PORT VALUE
	OR	AL,NOT (GATE2+SPK2)	; ISOLATE CURRENT SPEAKER BITS N CASE
	AND	AH,AL	;  SOMEONE TURNED THEM OFF DURING BEEP
	MOV	AL,AH	; RECOVER VALUE OF PORT
	AND	AL,NOT (GATE2+SPK2)	; FORCE SPEAKER DATA OFF
	OUT	PORT_B,AL	; AND STOP SPEAKER TIMER
	POPF		; RESTORE INTERRUPT FLAG STATE
	MOV	CX,1035	; FORCE 1/64 SECOND DELAY (SHORT)
	CALL	WAITF	; MINIMUM DELAY BETWEEN ALL BEEPS
	PUSHF		; SAVE INTERRUPT STATUS
	CLI		; BLOCK INTERRUPTS DURING UPDATE
	IN	AL,PORT_B	; GET CURRENT PORT VALUE IN CASE
	AND	AL,GATE2+SPK2	;  SOMEONE TURNED THEM ON
	OR	AL,AH	; RECOVER VALUE OF PORT_B
	OUT	PORT_B,AL	; RESTORE SPEAKER STATUS
	POPF		; RESTORE INTERRUPT FLAG STATE
	RET

BEEP	ENDP

;--- WAITF ---------------------------------------------------------------
;	FIXED TIME WAIT ROUTINE HARDWARE CONTROLLED - NOT PROCESSOR)	:
;				:
; ENTRY:				:
;	(CX) = COUNT OF 15.,085737 MICROSECOND INTERVALS TO WAIT	:
;		MEMORY REFRESH TIMER 1 OUTPUT USED AS REFERENCE	:
; EXIT:				:
;		AFTER (CX) TIME COUNT (PLUS OR MINUS 16 MICROSECONDS)	:
;	(CX) = 0		:
;-------------------------------------------------------------------------

WAITF	PROC	NEAR	; 	  DELAY FOR (CX)*15.085737 US
	PUSH	AX	; SAVE WORK REGISTER (AH)

WAITFI:			; USE TIMER 1 OUTPUT BITS
	IN	AL,PORT_B	; READ CURRENT COUNTER OUTPUT STATUS
	AND	AL,REFRESH_BIT	; MASK FOR REFRESH DETERMINE BIT
	CMP	AL,AH	; DID IT JUST CHANGE
	JE	WAITF1	; WAIT FOR A CHANCE IN OUTPUT LINE

	MOV	AH,AL	; SAVE NEW FLAG STATE
	LOOP	WAITF1	; DECREMENT HALF CYCLES TILL COUNT END

	POP	AX	; RESTORE (AH)
	RET		; RETURN (CX)= 0

WAITF	ENDP

;--- CONFIG_BAD ----------------------------------------------------------
;	SET CMOS_DIAG WITH CONFIG ERROR BIT (WITH NMI DISABLED)	:
;	(BP) BIT 14 SET ON TO INDICATE CONFIGURATION ERROR	:
;-------------------------------------------------------------------------

CONFIG_BAD	PROC	NEAR
	PUSH	AX
	MOV	AX,X*(CMOS_DIAG+NMI)	; ADDRESS CMOS DIAGNOSTIC STATUS BYTE
	CALL	CMOS_READ	; GET CURRENT VALUE
	OR	AL,BAD_CONFIG	; SET BAD CONFIGURATION BIT
	XCHG	AH,AL	; SETUP FOR WRITE
	CALL	CMOS_WRITE	; UPDATE CMOS WITH BAD CONFIGURATION
	POP	AX
	OR	BP,04000H	; SET CONFIGURATION BAD FLAG IN (BP)
	RET
CONFIG_BAD	ENDP


;--- XPC_BYTE -- XLATE_PR -- PRT_HEX -------------------------------------
;				:
;	CONVERT AND PRINT ASCII CODE CHARACTERS	:
;				:
;	AL CONTAINS NUMBER TO BE CONVERTED.	:
;	AX AND BX DESTROYED.		:
;-------------------------------------------------------------------------

XPC_BYTE	PROC	NEAR	;	  DISPLAY TWO HEX DIGITS
	PUSH	AX	; SAVE FOR LOW NIBBLE DISPLAY
	SHR	AL,4	; NIBBLE SWAP
	CALL	XLAT_PR	; DO THE HIGH NIBBLE DISPLAY
	POP	AX	; RECOVER THE NIBBLE
	AND	AL,0FH	; ISOLATE TO LOW NIBBLE
			; FALL INTO LOW NIBBLE CONVERSION

XLAT_PR	PROC	NEAR	; 	  CONVERT 00-0F TO ASCII CHARACTER
	ADD	AL,090H	; ADD FIRST CONVERSION FACTOR
	DAA		; ADJUST FOR NUMERIC AND ALPHA RANGE
	ADC	AL,040H	; ADD CONVERSION AND ADJUST LOW NIBBLE
	DAA		; ADJUST HIGH NIBBLE TO ASCII RANGE

PRT-HEX	PROC	NEAR
	MOV	AH,0EH	; DISPLAY CHARACTER IN (AL) COMMAND
	MOV	BH,0
	INT	10H	; CALL VIDEO_IO
	RET

PRT_HEX	ENDP
XLAT_PR	ENDP
XPC_BYTE	ENDP

;--- PRT_SEG ----------------------------------------------------
;	PRINT A SEGMENT VALUE TO LOOK LIKE A 21 BIT ADDRESS	:
;	DX MUST CONTAIN SEGMENT VALUE TO BE PRINTED	:
;----------------------------------------------------------------

PRT_SEG	PROC	NEAR
	MOV	AL,DH	; GET MSB
	CALL	XPC_BYTE	; DISPLAY SEGMENT HIGH BYTE
	MOV	AL,DL	; LSB
	CALL	XPC_BYTE	; DISPLAY SEGMENT LOW BYTE
	MOV	AL,'0'	; PRINT A '0 '
	CALL	PRT_HEX	; TO MAKE LOOK LIKE ADDRESS
	MOV	AL,' '	; ADD ENDING SPACE
	CALL	PRT_HEX
	RET
PRT_SEG 	ENDP

;--- PROT_PRT_HEX -------------------------------------------------------
;				:
;	PUT A CHARACTER TO THE DISPLAY BUFFERS WHEN IN PROTECTED MODE	:
;				:
;	(AL)= ASCII CHARACTER		:
;	(DI)= DISPLAY REGEN BUFFER POSITION	:
;------------------------------------------------------------------------

PROT_PRT_HEX	PROC	NEAR
	PUSH	ES	; SAVE CURRENT SEGMENT REGISTERS
	PUSH	DI
	SAL	DI,1	; MULTIPLY OFFSET BY TWO

;-----	MONOCHROME VIDEO CARD

	PUSH	BYTE PTR C_BWCRT_PTR	; GET MONOCHROME BUFFER SEGMENT SELECTOR
	POP	ES	; SET (ES) TO B/W DISPLAY BUFFER
	STOSB		; PLACE CHARACTER IN SUPPER
	DEC	DI	; ADJUST POINTER BACK

; ----- ENHANCED GRAPHICS ADAPTER

	PUSH	BYTE PTR E_CCRT_PTR	; ENHANCED COLOR DISPLAY POINTER LOW 64K
	POP	ES	; LOAD SEGMENT SELECTOR
	STOSB		; PLACE CHARACTER IN BUFFER
	DEC	DI	; ADJUST POINTER BACK
	PUSH	BYTE PTR E_CCRT_PTR2	; ENHANCED COLOR DISPLAY POINTER HI 64K
	POP	ES	; LOAD SEGMENT SELECTOR
	STOSB		; PLACE CHARACTER IN BUFFER
	DEC	DI	; ADJUST POINTER BACK

;-----	COMPATIBLE COLOR

	PUSH	BYTE PTR C_CCRT_PTR	; SET (OS) TO COMPATIBLE COLOR MEMORY
	POP	ES
	PUSH	BX	; SAVE WORK REGISTERS
	PUSH	DX
	PUSH	CX
	XOR	CX,CX	; TIMEOUT LOOP FOR "BAD" HARDWARE
	MOV	DX,03DAH	; STATUS ADDRESS OF COLOR CARD
	XCHG	AX,BX	; SAVE IN (BX) REGISTER
PROT_S:
	IN	AL,DX	; GET COLOR CARD STATUS
	TEST	AL,RVRT+RHRZ	; CHECK FOR VERTICAL RETRACE (OR HORZ)
	LOOPZ	PROT_S	; TIMEOUT LOOP TILL FOUND
	XCHG	AX,BX	; RECOVER CHARACTERS
	STOSB		; PLACE CHARACTER IN BUFFER
	POP	CX	; RESTORE REGISTERS
	POP	DX
	POP	BX
	POP	DI
	POP	ES
	RET

PROT_PRT_HEX 	ENDP

;------------------------------------------
;	ROM CHECKSUM SUBROUTINE	:
;------------------------------------------

RoM_CHECKSUM	PROC	NEAR
	SUB	CX,CX	; NUMBER OF BYTES TO ADD IS 64K

ROM_CHECKSUM_CNT:	; ENTRY FOR OPTIONAL ROM TEST
	XOR	AL,AL
ROM-L:
	ADD	AL,[BX]	; GET (DS:BX)
	INC	BX	; POINT TO NEXT BYTE
	LOOP	ROM_L	; ADD ALL BYTES IN ROM MODULE

	OR	AL,AL	; SUM = 0?
	RET

ROM_CHECKSUM 	ENDP

;------------------------------------------------------------------------
;	THIS ROUTINE CHECKSUMS OPTIONAL ROM MODULES AND	:
;	IF CHECKSUM IS OK, CALLS INITIALIZATION/TEST CODE IN MODULE	:
;------------------------------------------------------------------------

ROM_CHECK	PROC	NEAR
	MOV	AX,DATA	; POINT ES TO DATA AREA
	MOY	ES,AX
	SUB	AH,AH	; ZERO OUT AH
	MOV	AL,[BX+2]	; GET LENGTH INDICATOR
	SHL	AX,9	; MULTIPLY BY 512
	MOV	CX,AX	; SET COUNT
	SHR	AX,4
	ADD	DX,AX	; SET POINTER TO NEXT MODULE
	CALL	ROM_CHECKSUM_CNT	; DO CHECKSUM
	JZ	ROM_CHECK_1

	CALL	ROM_ERR	; POST CHECKSUM ERROR
	JMP	SHONT ROM_CHECK_END	; AND EXIT

ROM_CHECK_1:
	PUSH	DX	; SAVE POINTER
	MOV	ES:@IO_ROM_INIT,0003H	; LOAD OFFSET
	MOV	ES:@IO_ROM_SEG,DS	; LOAD SEGMENT
	CALL	DWORD PTR ES:@IO_ROM_INIT	; CALL INITIALIZE/TEST ROUTINE
	POP	DX

ROM_CHECK_END:
	RET		; RETURN TO CALLER

ROM_CHECK	ENDP

;--- KBD_RESET-----------------------------------------------------------
;	THIS PROCEDURE WILL SEND A SOFTWARE RESET TO THE KEYBOARD.	:
;	SCAN CODE 0AAH SHOULD BE RETURNED TO THE PROCESSOR.	:
;	SCAN CODE 065H IS DEFINED FOR MANUFACTURING TEST	:
;------------------------------------------------------------------------

KBD_RESET	PROC 	NEAR
	MOV	AL,0FFH	; SET KEYBOARD RESET COMMAND
	CALL	XMIT_8042	; GO ISSUE THE COMMAND
	JCXZ	G13	; EXIT IF ERROR

	CMP	AL,KB_ACK
	JNZ	G13

	MOV	AL,0FDH	; ENABLE KEYBOARD INTERRUPTS
	OUT	INTA01,AL	; WRITE 8259 INTERRUPT MASK REGISTER
	MOV	@INTR_FLAG,0	; RESET INTERRUPT INDICATOR
	STI		; ENABLE INTERRUPTS
	MOV	BL,10	; TRY FOR 400 MILLISECONDS
	SUB	CX,CX	; SETUP INTERRUPT TIMEOUT COUNT
G11:
	TEST	@INTR_FLAG,02H	; DID A KEYBOARD INTERRUPT OCCUR 7
	JNZ	G12	; YES - READ SCAN CODE RETURNED
	LOOP	GI1	; NO - LOOP TILL TIMEOUT

	DEC	BL
	JNZ	G11	; TRY AGAIN
G12:
	IN	AL,PORT_A	; READ KEYBOARD SCAN CODE
	MOV	BL,AL	; SAVE SCAN CODE JUST READ
G13:
	RET		; RETURN TO CALLER

KBD_RESET	ENDP

;--------------------------------------------------------
;	BLINK LED PROCEDURE FOR MFG RUN-IN TESTS	:
;	 IF LED IS ON, TURN IT OFF. IF OFF, TURN ON.	:
;--------------------------------------------------------

BLINK_INT	PROC	NEAR
	STI
	PUSH	AX	; SAVE AX REGISTER CONTENTS
	IN	AL,MFG_PORT	; READ CURRENT VALUE OF MFG_PORT
	XOR	AL,01000000B	; FLIP CONTROL BIT
	OUT	MFG_PORT,AL
	MOY	AL,EOI
	OUT	INTA00,AL
	POP	AX	; RESTORE AX REGISTER
	IRET
BLINK_INT	ENDP

;-------------------------------------------------------------------------------
;	THIS ROUTINE INITIALIZES THE TIMER DATA AREA IN THE ROM BIOS	:
;	DATA AREA.  IT IS CALLED BY THE POWER ON ROUTINES.  IT CONVERTS	:
;	HR:MIN:SEC  FROM CMOS TO TIMER TICS. IF CMOS IS INVALID, TIMER	:
;	IS SET TO ZERO.		:
;				:
; INPUT	NONE PASSED TO ROUTINE BY CALLER		:
;	CMOS LOCATIONS USED FOR TIME		:
;				;
; OUTPUT	@TIMER_LOW		:
;	@TIMER_HIGH		:
;	@TIMER_OFL		:
;	ALL REGISTERS UNCHANGED		:
;-------------------------------------------------------------------------------

COUNTS_SEC 	EQU	18	; TIMER DATA CONVERSION EQUATES
COUNTS_MIN	EQU	1092
COUNTS_HOUR	EQU	7	; 65543 - 65536
UPDATE_TIMER	EQU	10000000B	; RTC UPDATE IN PROCESS BIT MASK

SET_TOD	PROC	NEAR
	PUSHA
	PUSH	DS
	CALL	DDS	; ESTABLISH SEGMENT
	SUB	AX,AX
	MOV	@TIMER_OFL,AL	; RESET TIMER ROLL OVER INDICATOR
	MOV	@TIMER_LOW,AX	; AND TIMER COUNT
	MOV	@TIMER_HIGH,AX
	MOV	AL,CMOS_DIAG+NMI	; CHECK CMOS VALIDITY
	CALL	CMOS_READ	; READ DIAGNOSTIC LOCATION IN CMOS
	AND	AL,BAD_BAT+BAD_CKSUM+CMOS_CLK_FAIL
	SUB	CX,CX	; BAD BATTERY, CHKSUM ERROR, CLOCK ERROR
	JNZ	POD_DONE	; CMOS NOT VALID -- TIMER SET TO ZERO
UIP:
	MOV	AL,CMOS_REG_A+NMI	; ACCESS REGISTER A
	CALL	CMOS_READ	; READ CMOS CLOCK REGISTER A
	TEST	AL,UPDATE_TIMER
	LOOPZ	UIP	; WAIT TILL UPDATE BIT IS ON

	JCXZ	POD_DONE	; CMOS CLOCK STUCK IF TIMEOUT
UIPOFF:
	MOV	AL,CMOS_REG_A+NMI	; ACCESS REGISTER A
	CALL	CMOS_READ	; READ CMOS CLOCK REGISTER A
	TEST	AL,UPDATE_TIMFR
	LOOPNZ	UIPOFF	; NEXT WAIT TILL END OF UPDATE

	JCXZ	POD_DONE	; CMOS CLOCK STUCK IF TIMEOUT

	MOV	AL,CMOS_SECONDS+NMI	; TIME JUST UPDATED
	CALL	CMOS_READ	; ACCESS SECONDS VALUE IN CMOS
	CMP	AL,59H	; ARE THE SECONDS WITHIN LIMITS?
	JA	TOD_ERROR	; GO IF NOT

	CALL	CVT_BINARY	; CONVERT IT TO BINARY
	MOV	CX,AX	; MOVE COUNT TO ACCUMULATION REGISTER
	SHR	CX,2	; ADJUST FOR SYSTEMATIC SECONDS ERROR
	MOV	BL,COUNTS_SEC
	MUL	BL	; COUNT FOR SECONDS
	ADD	CX,AX
	MOV	AL,CMOS_MINUTES+NMI
	CALL	CMOS_READ	; ACCESS MINUTES VALUE IN CMOS
	CMP	AL,59H	; ARE THE MINUTES WITHIN LIMITS?
	JA	TOD_ERROR	; GO IF NOT
	CALL	CYT_BINARY	; CONVERT IT TO BINARY
	PUSH	AX	; SAVE MINUTES COUNT
	SHR	AX,1	; ADJUST FOR SYSTEMATIC MINUTES ERROR
	ADD	CX,AX	; ADD ADJUSTMENT TO COUNT
	POP	AX	; RECOVER BCD MINUTES VALUE
	MOV	BX,COUNTS_MIN
	MUL	BX	; COUNT FOR MINUTES
	ADD	CX,AX	; ADD TO ACCUMULATED VALUE
	MOV	AL,CMOS_HOURS+NMI
	CALL	CMOS_READ	; ACCESS HOURS VALUE IN CMOS
	CMF	AL,23H	; ARE THE HOURS WITHIN LIMITS?
	JA	TOD_ERROR	; GO IF NOT

	CALL	CVT_BINARY	; CONVERT IT TO BINARY
	MOV	DX,AX
	MOV	BL,COUNTS_HOUR
	MUL	BL	; COUNT FOR HOURS
	ADD	AX,CX
	ADC	DX,0000H
	MOV	@TIMER_HIGH,DX
	MOV	@TIMER_LOW,AX
POD_DONE:
	POP	DS
	POPA
	RET

TOD_ERROR:
	POP	DS	; RESTORE SEGMENT
	POPA		; RESTORE REGISTERS
	MOV	SI,OFFSET E163	; DISPLAY CLOCK ERROR
	CALL	E_MSG
	MOV	AX,X*(CMOS_DIAG+NMI)	; SET CLOCK ERROR IN STATUS
	CALL	CMOS_READ	; READ DIAGNOSTIC CMOS LOCATION
	OR	AL,CMOS_CLK_FAIL	; SET NEW STATUS WITH CMOS CLOCK ERROR
	XCHG	AL,AH	; MOVE NEW STATUS TO WORK REGISTER
	CALL	CMOS_WRITE	; UPDATE STATUS LOCATION
	RET
SET_TOD 	ENDP

CVT_BINARY	PROC	NEAR
	MOV	AH,AL	; UNPACK 2 BCD DIGITS IN AL
	SHR	AH,4
	AND	AL,0FH	; RESULT IS IN AX
	AAD		; CONVERT UNPACKED BCD TO BINARY
	RET
CVT_BINARY	ENDP

;--- D11 -- INT ?? H - ( IRQ LEVEL ?? ) ---------------------------------------
; TEMPORARY INTERRUPT SERVICE ROUTINE FOR POST	:
;				:
;	THIS ROUTINE IS ALSO LEFT IN PLACE AFTER THE POWER ON DIAGNOSTICS	:
;	TO SERVICE UNUSED INTERRUPT VECTORS.  LOCATION "@INTR_FLAG" WILL	:
;	CONTAIN EITHER:		:
;	 1) LEVEL OF HARDWARE INTERRUPT THAT CAUSED CODE TO BE EXECUTED, OR	:
;	 2) "FF" FOR A NON-HARDWARE INTERRUPT THAT WAS EXECUTED ACCIDENTALLY.:
;------------------------------------------------------------------------------

D11	PROC	NEAR
	PUSH	AX	; SAVE REGISTER AX CONTENTS
	PUSH	BX
	MOV	AL,0BH	; READ IN-SERVICE REGISTER
	OUT	INTA00,AL	; (FIND OUT WHAT LEVEL BEING
	JMP	$+2	;  SERVICED)
	IN	AL,INTA00	; GET LEVEL
	MOV	AH,AL	; SAVE IT
	OR	AL,AH	; 00? (NO HARDWARE ISR ACTIVE)
	JNZ	HW_INT

	MOV	AH,0FFH
	JMP	SHORT SET_INTR_FLAG	; SET FLAG TO "FF" IF NON-HARDWARE
HW_INT:
	MOV	AL,0BH	; READ IN-SERVICE REGISTER FROM
	OUT	INTB00,AL	; INTERRUPT CHIP #2
	JMP	$+2	; I/O DELAY
	IN	AL,INTB00	; CHECK THE SECOND INTERRUPT CHIP
	MOV	BH,AL	; SAVE IT
	OR	BH,BH
	JZ	NOT_SEC	; CONTINUE IF NOT

	IN	AL,INTB01	; GET SECOND INTERRUPT MASK
	OR	AL,BH	; MASK OFF LEVEL BEING SERVICED
	JMP	$+2	; I/O DELAY
	OUT	INTB01,AL
	MOV	AL,EOI	; SEND EOI TO SECOND CHIP
	JMP	$+2	; I/O DELAY
	OUT	INTB00,AL
	JMP	SHORT IS_SEC
NOT_SEC:
	IN	AL,INTA01	; GET CURRENT MASK VALUE
	JMP	$+2	; I/O DELAY
	AND	AH,0FBH	; DO NOT DISABLE SECOND CONTROLLER
	OR	AL,AH	; MASK OFF LEVEL BEING SERVICED
	OUT	INTA01,AL	; SET NEW INTERRUPT MASK
	JMP	$+2	; I/O DELAY
IS_SEC:
	MOV	AL,EOI
	OUT	INTA00,AL
SET_INTR_FLAG:
	POP	BX	; RESTORE (BX) FROM STACK
	PUSH	DS	; SAVE ACTIVE (DS)
	CALL	DDS	; SET DATA SEGMENT
	MOV	@INTR_FLAG,AH	; SET FLAG
	POP	DS
	POP	AX	; RESTORE REGISTER AX CONTENTS
DUMMY_RETURN_1:		; NEED IRET FOR VECTOR TABLE
	IRET

D11 	ENDP

;--- HARDWARE INT 71 H -- ( IRQ LEVEL 9 ) -- TO INT  0A H ---------------------
; REDIRECT SLAVE INTERRUPT 9 TO INTERRUPT LEVEL 2	:
;	THIS ROUTINE FIELDS LEVEL 9 INTERRUPTS AND	:
;	CONTROL IS PASSED TO WASTER INTERRUPT LEVEL 2	:
;------------------------------------------------------------------------------

RE_DIRECT PROC 	NEAR
	PUSH	AX	; SAVE (AX)
	MOV	AL,EOI
	OUT	INTB00,AL	; EOI TO SLAVE INTERRUPT CONTROLLER
	POP	AX	; RESTORE [AX]
	INT	0AH	; GIVE CONTROL TO HARDWARE LEVEL 2
	
	IRET		; RETURN

RE_DIRECT ENDP

;--- HARDWARE INT 75 H -- ( IRO LEVEL 13 ) ------------------------------------
; SERVICE X287 INTERRUPTS		:
;	THIS ROUTINE FIELDS X287 INTERRUPTS AND CONTROL	:
;	IS PASSED TO THE NMI INTERRUPT HANDLER FOR 	:
;	COMPATIBILITY.		:
;------------------------------------------------------------------------------

INT_287	PROC	NEAR
	PUSH	AX	; SAVE (AX)
	XOR	AL,AL
	OUT	X287,AL	; REMOVE THE INTERRUPT REQUEST

	MOV	AL,EOI	; ENABLE THE INTERRUPT
	OUT	INTB00,AL	;  THE SLAVE
	OUT	INTA00,AL	;  THE MASTER
	POP	AX	; RESTORE (AX)
	INT	02H	; GIVE CONTROL TO NMI

	IRET		; RETURN

INT_287 ENDP

PROC_SHUTDOWN	PROC	; 	  COMMON 80286 SHUTDOWN WAIT

	MOV	AL,SHUT_CMD	; SHUTDOWN COMMAND
	OUT	STATUS_PORT,AL	; SEND TO KEYBOARD CONTROL PORT

PROC_S:
	HLT		; WAIT FOR 80256 RESET
	JMP	PROC_S	; INSURE HALT

PROC_SHUTDOWN	ENDP
CODE	ENDS
	END
