;
; PROGRAM TO TEST M-DRIVE/H BOARDS.  Will test up to 8 boards, and can
;  skip nonexistent boards.
;	2/21/83		LLO
;
;  FOR ROM VERSION - MEMORY MAP LOOKS AS FOLLOWS (USE A RAM 16)
;
;	0F_0000H +---------------------------------------
;		 |     STACK SPACE
;	0F_0100H +---------------------------------------
;		 |     
;		 |     DATA SPACE
;		 |
;		 |
;	0F_F000H +--------------------------------------
;		 |
;		 |     CODE SPACE (IN ROM)
;		 |
;	0F_FFF0H +--------------------------------------
;		 |     8086 RESET VECTOR
;	0F_FFFFH +--------------------------------------
;
HBASE   equ     0C6H            ;BASE OF HDRIVE BOARD
HDATA   EQU     HBASE
HADDR   EQU     HBASE + 1       
MAXBORD EQU     8
;
FALSE   EQU     0
TRUE    EQU     NOT FALSE
CPM     EQU     TRUE            ;FALSE FOR ROMMABLE VERSION
CR      EQU     0AH
LF      EQU     0DH     
BASE16  EQU     16
BASE10  EQU     10
BASE2   EQU     2
ALLOC	EQU	55		;CPM ALLOCATE MEMORY FUNCTION
FREEMEM	EQU	57		;CPM FUNCTION TO RETURN ABOVE
;
RAMSEG  EQU     0F000H         ;START OF RAM WE WILL USE
				;RAM 16 AT TOP OF 1 MEG
ROMSEG	EQU	0FF00H		; WITH 4K OF ROM AT TOP
        
        CSEG
;INITIALIZE THINGS
START:
        IF      NOT CPM         ;IF NOT CPM MUST SET OUR OWN SEGMENTS
        ORG     0FF000H         ;PUT PROGRAM AT TOP OF MEMORY
        MOV     BX,RAMSEG       ;START OF RAM
        MOV     DS,BX
        MOV     SS,BX		;SS AND DS CAN BE SAME
        MOV     SP,0FFH		;LOTS OF STACK SPACE
        MOV     BX,ESSEG	;
        MOV     ES,BX           ;SET ES TO MESSAGE AREA ( IN ROM )
        CALL    I4INIT          ;INITIALIZE I/O4
	MOV	BX,OFFSET DIGIT1;INITIALIZE COUNTER
	MOV	AL,'0'
	MOV	BYTE PTR [BX],AL
	INC	BX
	MOV	BYTE PTR [BX],AL
	INC	BX
	MOV	BYTE PTR [BX],AL
        ENDIF
	MOV	BX,OFFSET CPYMSG
	CALL	PRINT		;PRINT COPYRIGHT MESSAGE
;FIRST DO BOARD SEARCH
        MOV     CL,7
        MOV     BX,0FFFFH       ;CHECK TOP OF BOARDS
        MOV     SI,OFFSET F_BORD
SIZLOP: MOV     AL,CL
        CALL    SET
        MOV     AL,0            ;WRITE OUT A 0  
        OUT     HDATA,AL          
        MOV     AL,CL           ;
        CALL    SET
        IN      AL,HDATA
        MOV     [SI],AL         ;SET VALUE RETURNED INTO ARRAY
        INC     SI
        ADD     CL,8            ;NEXT BOARD
        CMP     CL,MAXBORD*8    ;UP TO 8 BOARDS,8 INCREMENTS PER BOARD
        JL      SIZLOP          ;IF MORE TO DO
        MOV     AL,1            ;PRINT "FOUND " MESSAGES
        MOV     SI,OFFSET F_BORD
PEXIST: PUSH    AX              ;SAVE CURRENT BOARD NUMBER
        MOV     BX,OFFSET EXITS ;"BOARD # " MESSAGE


        CALL    PRINT
        POP     CX              ;GET CURRENT BOARD
        PUSH    CX      
        ADD     CL,'0'          ;ADD IN ASCII OFFSET
        CALL    CONO            ;AND PRINT IT
        MOV     AL,[SI]         ;GET FLAG FOR THIS BOARD
        MOV     BX,OFFSET YESEX ;YES IT EXISTS MESSAGE
        CMP     AL,0FFH         ;WAS IT THERE
        JNZ     EXISTS  
        MOV     BX,OFFSET NOEX  ;NO IT DOES NOT EXIST
EXISTS: CALL    PRINT           ;PRINT EXISTS OR NOT MESSAGE
        POP     AX
        INC     SI              ;UP TO NEXT FLAG
        INC     AL              ;UP TO NEXT BOARD
        CMP     AL,MAXBORD      ;
        JLE     PEXIST
;
;***********************************************************
; NOW START TESTING
TSTSTRT:MOV     SI,OFFSET F_BORD-1
        MOV     BYTE PTR CURBORD,1      ;SET CURRENT BOARD TO 1
TESTLP:
        XOR     BH,BH
;       MOV     BYTE PTR ERRCNT,BH      ;ZERO ERROR COUNTER FOR THIS BOARD
        MOV     BL,BYTE PTR CURBORD     ;GET FLAG
        CMP     BYTE PTR (OFFSET F_BORD-1)[BX],0FFH   ;
        JNE     TST1
        JMP     NEXT_BD                 ;DO NEXT BOARD
TST1:   PUSH    BX                      ;SAVE CURRENT SPOT
        MOV     BX,OFFSET TSTMSG        ;TESTING MESSAGE
        CALL    PRINT
        POP     CX
        ADD     CL,'0'                  ;ADD IN ASCII BIAS
        CALL    CONO                    ;AL HAS NUMBER OF BOARD
	IF	CPM			;PRINT A CR ONLY IF TO TERMINAL
        CALL    CRLF2
	ENDIF
        MOV     BX,OFFSET OOMSG ;TESTING MESSAGE
        CALL    PRINT
        MOV     AL,BYTE PTR CURBORD     ;GET CURRENT BOARD AGAIN
        DEC     AL
        SHL AL,1 ! SHL AL,1 ! SHL AL,1          ;MAKE ADDRESS
        MOV     BX,0
        MOV     AH,0                    ;FILL WITH ZEROS
        MOV     CX,0
        MOV     DI,8                    ;FILL 80000 TIMES
        PUSH    AX ! PUSH BX ! PUSH DI ! PUSH CX
        CALL    FILL
        POP  CX ! POP DI ! POP BX ! POP AX
        PUSH    AX ! PUSH BX ! PUSH DI ! PUSH CX
        CALL    VERIFY
        JZ      NOERR1                  ;IF NOT ERROR GO ON
        CALL    ERROR                   ;IF ERROR GO PRINT MESSAGE AND CONTINUE
        JMP     NEXT_BD                 ;WE GOT AN ERROR SO SKIP THIS BOARD

NOERR1:
        POP  CX ! POP DI ! POP BX ! POP AX
;NOW FILL ENTIRE BOARD WITH 0FFH
        MOV     BX,OFFSET FFMSG 
        CALL    PRINT
        MOV     AL,BYTE PTR CURBORD
        DEC     AL
        SHL AL,1 ! SHL AL,1 ! SHL AL,1 
        MOV     BX,0
        MOV     AH,0FFH
        MOV     CX,0
        MOV     DI,8                    ;FILL FF 80000 TIMES
        PUSH    AX ! PUSH BX ! PUSH DI ! PUSH CX
        CALL    FILL
        POP  CX ! POP DI ! POP BX ! POP AX
        PUSH    AX ! PUSH BX ! PUSH DI ! PUSH CX
        CALL    VERIFY
        JZ      NOERR2                  ;IF NOT ERROR GO ON
        CALL    ERROR                   ;IF ERROR GO PRINT MESSAGE AND CONTINUE
        JMP     NEXT_BD
NOERR2:
        POP  CX ! POP DI ! POP BX ! POP AX
;NOW DO A 55 TEST 
        MOV     BX,OFFSET O55MSG        
        CALL    PRINT
        MOV     AL,BYTE PTR CURBORD
        DEC     AL
        SHL AL,1 ! SHL AL,1 ! SHL AL,1 
        MOV     BX,0
        MOV     AH,055H
        MOV     CX,0
        MOV     DI,8                    ;FILL 512K TIMES
        PUSH    AX ! PUSH BX ! PUSH DI ! PUSH CX
        CALL    FILL
        POP  CX ! POP DI ! POP BX ! POP AX
        PUSH    AX ! PUSH BX ! PUSH DI ! PUSH CX
        CALL    VERIFY
        JZ      NOERR3                  ;IF NOT ERROR GO ON
        CALL    ERROR                   ;IF ERROR GO PRINT MESSAGE AND CONTINUE
        JMP     NEXT_BD
NOERR3:
        POP  CX ! POP DI ! POP BX ! POP AX
;
; ADDRESS LINE TEST
; first test location 0
ADRTST: MOV     BX,OFFSET ADRMSG
        CALL    PRINT
        MOV     AH,0AAH
        MOV     AL,BYTE PTR CURBORD     ;GET CURRENT BOARD
        DEC     AL
        SHL     AL,1 ! SHL AL,1 ! SHL AL,1
        MOV     BX,0
        MOV     CX,1
        MOV     DI,0            ;FILL JUST ONE BYTE
        PUSH AX ! PUSH BX ! PUSH DI ! PUSH CX
        CALL    FILL
        POP CX ! POP DI ! POP BX ! POP AX
        MOV     DI,7
        MOV     CX,0FFFFH
        MOV     BX,1
        MOV     AH,55H
        PUSH AX ! PUSH BX ! PUSH DI ! PUSH CX
        CALL    VERIFY
        JZ      NOERR4
        CALL    ERROR
        JMP     NEXT_BD
NOERR4:         
        POP CX ! POP DI ! POP BX ! POP AX
        MOV     BX,1
        MOV     AL,BYTE PTR CURBORD
        DEC     AL
        SHL AL,1 ! SHL AL,1 ! SHL AL,1
ADDRLP: MOV     AH,55H
        PUSH    AX ! PUSH BX
        MOV     CX,1
        MOV     DI,0
        PUSH AX ! PUSH BX ! PUSH DI ! PUSH CX
        CALL    FILL
        POP CX ! POP DI ! POP BX ! POP AX
        INC     BX
        ADC     AL,0
;WANT DI:CX = 512K - AL:BX
        PUSH    AX              ;SAVE AX
        MOV     DX,AX
        MOV     AH,0
        MOV     CL,8
        DIV     CL
        DEC     AH
        MOV     AL,7
        MOV     CX,0
        SUB     CX,BX
        SBB     AL,AH
        MOV     AH,0
        MOV     DI,AX
        POP     AX
        PUSH AX ! PUSH BX ! PUSH DI ! PUSH CX
        CALL    VERIFY
        JZ      NOERR5
        CALL    ERROR
        JMP     NEXT_BD
NOERR5:
        POP CX ! POP DI ! POP BX ! POP AX
        POP BX ! POP AX 
        SHL     BX,1                    ;NEXT ADDRESS TO TEST
        JNBE    ADDRLP                  ;NO NEED TO CHANGE AL SO MOVE ON
        PUSHF                           ;LETS SAVE CARRY FLAG
        MOV     CL,AL
        AND     AL,00000111B            ;GET BOARD LOCATION
        AND     CL,11111000B            ;GET BOARD #
        POPF                            ;GET CARRY FLAG BACK
        RCL     AL,1                    ;SHIFT IN CARRY FLG IF NEEDED
        TEST    AL,8                    ;WHEN AL IS 8 WE ARE DONE
        JZ      ADRDON  
        OR      AL,CL                   ;PUT BOARD LOCATION WITH BOARD #
        JMP     ADDRLP                  ;AL FIXED SO MOVE ON
;
ADRDON:
; DO A RANDOM DATA FILL AND VERIFY.  THE CODE SEGEMENT IS USED
; TO GET RANDOM DATA
	MOV	BX,OFFSET RANDMSG
	CALL	PRINT
;	
	PUSH	ES
	IF	CPM
	PUSH	DS
	PUSH	DS
	POP	ES		;DS -> ES FOR MOVE
	PUSH	CS
	POP	DS		;CS -> DS FOR MOVE
	MOV	SI,0		;
	MOV	DI,OFFSET SAVBUF	;TO BUFFER IN DS
	MOV	CX,(4 * 1024)/2	;MOVE 4K WORTH
	REP	MOVSW		;TO NEW SPOT
	POP	DS		;RESTORE DS
	ENDIF
	IF	NOT CPM		;IF ROM VERSION, WILL HAVE 4K OF ROM,USE THAT
	PUSH	CS
	POP	ES		;CS -> ES
	ENDIF
	MOV	AL,BYTE PTR CURBORD
	DEC	AL		;MAKE BOARD # INTO ADDRESS	
	SHL AL,1 ! SHL AL,1 ! SHL AL,1 !
	MOV	BX,0		;ALWAYS START AT BOTTOM OF BOARD
	PUSH	DS ! PUSH AX ! PUSH BX
;	
	CALL	SET		;SET THE BOARD TO AL:BX
	PUSH	ES
	POP	DS		;PREPARE FOR LODS ES -> DS
	MOV	DX,HDATA
	MOV	CX,512 / 4	;DO THIS MANY OF 4K CHUNKS
WRTCHK:	PUSH	CX		;SAVE COUNT	
	MOV	SI,OFFSET SAVBUF
	MOV	CX,4 * 1024	;DO 4K TIMES
WRTCH2:	LODSB			;GET A BYTE INTO AL
	OUT	DX,AL		;AND OUTPUT IT
	LOOP	WRTCH2		;4K TIMES
	POP	CX
	LOOP	WRTCHK		;DO THIS LOOP 128 TIMES
;
;NOW VERIFY BOARD
	POP BX 	! POP AX ! 	;GET START ADDR BACK
	POP	DS		;DONE WITH DS, RESTORE IT
	PUSH AX ! PUSH BX	;AND SAVE FOR ERROR
	CALL	SET		;AND RESET MDRIVE/H
	MOV	CX,512 / 4	;AGAIN 128-4K CHUNKS
REDCHK:	PUSH	CX
	MOV	DI,OFFSET SAVBUF	;ES ALREADY SET
	MOV	CX,4 * 1024
REDCH2:	IN	AL,DX		;GET BYTE FROM M-DRIVE/H
	SCASB			;COMPARE IT WITH CODE
	LOOPE 	REDCH2		;DO MORE IF NO ERROR	
	JNE	ERR6		;PROCESS ERROR IF OCCURED
	POP	CX
	LOOP	REDCHK		;ELSE GO DO NEXT 4K
;HERE BOARD SHOULD BE GOOD
	POP BX ! POP AX		;RESTORE STACK
	POP	ES
	JMP	NEXT_BD
;
;
;   PROCESS ERROR FROM RANDOM FILL ROUTINE
ERR6:
	POP	BX		;# 4K CHUNKS LEFT TO DO
	POP	SI		;GET OLD BX
	POP	DX		;GET OLD AX
	POP	BP		;SAVE OLD ES
	PUSH	DX		;PUT OLD AX BACK
	PUSH	SI		;AND SAME FOR OLD BX
	MOV	DX,8		;WANTED TO DO 512K CHECKS
	PUSH	DX
	MOV	DX,0
	PUSH	DX		;STACK IS NOW SET FOR ERROR ROUTINE
	DEC	DI		;POINT DI TO FAILED SHOULD BE BYTE
	MOV	AH,ES:[DI]	;SHOULD BE IN AH,WAS IN AL
	PUSH	AX		;SAVE FOR LATER
	MOV	AX,4*1024	;4K...
	DEC	BX		; -1 JUST DONE
	MUL	BX		;...* # OF CHUNKS LEFT TO DO
	ADD	CX,AX		;# BYTE IN 4K LEFT TO DO
	ADC	DX,0		;DX IS OVERFLOW FROM MUL + CARRY OF ADD
	MOV	DI,DX		;HIGH BYTE OF # OF CHECKS LEFT TO DO
	POP	AX		;SHOULD AND WAS
	PUSH	BP
	POP	ES		;RESTORE ES
	CALL	ERROR		;GO PROCESS ERROR
;	JMP	NEXT_BD		;AND DO NEXT BOARD
;
	
NEXT_BD:
        MOV     AL,BYTE PTR CURBORD
        INC     AL
        MOV     BYTE PTR CURBORD,AL
        CMP     AL,8
        JG      EXIT
        JMP     TESTLP
EXIT:
	IF	NOT CPM
        MOV     BX,OFFSET DONMSG
        CALL    PRINT
	ENDIF
FINIS:
        IF      CPM
	CALL	CRLF2
      	MOV     BX,OFFSET PASSMSG
       	CALL    PRINT
       	CALL    CYCCNT          ;UPDATE PASS COUNTER
       	CALL    SCORE           ;PRINT IT
       	JMP     TSTSTRT         ;AND DO OVER
	CALL	CRLF
       	ENDIF
       	IF      NOT CPM
       	JMP     FINIS           ;DYNAMIC STALL FOR ROM
       	ENDIF
;
;***************************************************
;
;  ERROR - Print a message and up error counter
; 
;    ENTRY - STACK: (+0) = RETURN ADDRESS 
;                   (+1) = LOW WORD OF NUMBER OF CHECKS TO DO
;                   (+2) = HIGH BYTE OF NUMBER OF CHECKS  
;                   (+3) = ADDRESS USED TO START CHECK
;                   (+4) = UPPER BYTE OF ADDRESS USED TO START
;
;       REGISTERS - CX = LOW WORD OF NUMBER OF CHECKS LEFT TO DO
;                   DI = HIGH BYTE OF NUMBER OF CHECKS LEFT TO DO
;                   AH = SHOULD BE BYTE
;                   AL = WAS BYTE
;
;*******************************************************
;
ERROR:  POP     BP              ;SAVE RETURN ADDRESS
        POP     DX
        POP     BX
        SUB     DX,CX
E1:     SBB     BX,DI           ;UPPER BYTE
        POP     DI
        POP     CX
        XOR     CH,CH           ;CLEAR UPPER BYTE
        ADD     DX,DI
E2:     ADC     BX,CX
        SUB     DX,1
        SBB     BX,0
; HERE BX:DX HAVE ADDRESS THAT FAILED
;      AH = SHOULD BE BYTE
;      AL = WAS BYTE
        PUSH    AX
        PUSH    BX              ;SAVE ROW AND COLUMN
        PUSH    AX
        MOV     CL,12           ;PUT MOST OF NUMBER INTO BX
        MOV     AX,DX           ;FOR PRINT
        SHL     BX,CL
        MOV     CL,4
        SHR     AX,CL
        OR      BX,AX
        AND     DX,000FH        ;MASK OFF UPPER BITS
        POP     AX
        PUSH    DX
        PUSH    BX
        PUSH    AX
        MOV     BX,OFFSET ERR1MSG
        CALL    PRINT
        POP     AX
        PUSH    AX
        MOV     AL,AH
        XOR     AH,AH
        MOV     BX,BASE16
        CALL    PUTN            ;PRINT SHOULD BE
        MOV     BX,OFFSET ERR2MSG
        CALL    PRINT
        POP     AX
        XOR     AH,AH
        MOV     BX,BASE16
        CALL    PUTN            ;PRINT WAS
        MOV     BX,OFFSET ERR3MSG
        CALL    PRINT
        POP     AX
        MOV     BX,BASE16
        CALL    PUTN            ;PRINT HIGH WORD OF ADDRESS
        POP     AX
        MOV     BX,BASE16
        CALL    PUTN            ;PRINT LOW WORD OF ADDRESS
        CALL    CRLF2
        POP     CX
        ADD     CL,'0'          ;ADD IN ASCII OFFSET
        POP     AX
        PUSH    CX              ;SAVE ROW NUMBER
        XOR     AL,AH
        MOV     CX,'0'-1
E3:     INC     CX
        CMP     CX,'9'
        JGE     E4
        CLC
        RCR     AL,1
        JNC     E3
        PUSH    AX
        PUSH    CX              ;PRINT BIT NUMBER 
        MOV     BX,OFFSET ERR4MSG       ;PRINT ROW MESSAGE
        CALL    PRINT
        POP     AX
        POP     BX              ;GET BIT MAP OUT
        POP     CX              ;GET ROW NUMBER
        PUSH    CX              ;SAVE ROW NUMBER
        PUSH    BX              ;SAVE BIT MAP 
        PUSH    AX              ;SAVE ASCII BIT #
        CALL    CONO            ;PRINT ROW NUMBER
        MOV     BX,OFFSET ERR5MSG
        CALL    PRINT
        POP     CX
        PUSH    CX
        CALL    CONO            ;PRINT COLUMN NUMBER
        CALL    CRLF
        POP     CX
        POP     AX              ;GET BAD BITS MAP BACK
        JMP     E3
E4:     POP     CX              ;FIX STACK
        CALL    CRLF            
        NOP
;       INT     3
        PUSH    BP              ;RETURN ADDRESS
        RET
;                       
;
;
;********************************************************
;*                                                      *       
;*      SET - Set the HDRIVE board address              *
;*            counters                                  *
;*      ENTRY - AL,BX 24 Bit address to set             *
;*                                                      *       
;*      EXIT - board is set                             *       
;*                                                      *       
;********************************************************
SET:    OUT     HADDR,AL
        MOV     AL,BH
        OUT     HADDR,AL
        MOV     AL,BL
        OUT     HADDR,AL
        RET
;
;******************************************************
;
;   FILL - Fill the HDRIVE board with a value
;
;     ENTRY - AL,BX = Address to start filling at.
;             DI,CX = # Bytes to write to HDRIVE
;             AH = Byte to write to HDRIVE
;
;     EXIT - Board is filled with AH
;
;*******************************************************
;
FILL:   PUSH    DX              ;SAVE DX
        CALL    SET             ;SET HDRIVE BOARD
        MOV     DX,HDATA        ;FOR FAST OUT
        MOV     AL,AH           ;GET BYTE TO OUT
        CMP     CX,0            ;
        JE      FILL1           ;IF NO VALUE IN CX
FILL0:  OUT     DX,AL           ;OUTPUT BYTE TO BOARD CX TIMES
        LOOP    FILL0           ;
FILL1:  CMP     DI,0            ;DI IS HIGH BYTE OF COUNTER
        JE      FILLOT          ;IF BOTH CX & DI 0
        XOR     CX,CX           ;MAX COUNT IS 0 FOR CX COUNTER
FILL2:  OUT     DX,AL
        LOOP    FILL2           ;UNTIL CX IS 0
        DEC     DI              ;
        JMP     FILL1           ;AND DO AGAIN
FILLOT: POP     DX              ;RESTORE DX
        RET
;       
;
;******************************************************
;
;       VERIFY - Verify that HDRIVE board has given 
;                byte in given range
;
;        ENTRY - AL,BX = Address to start checking from
;                DI,CX = # Bytes to check
;                AH    = Byte to check
;
;        EXIT - Z bit set if error
;
;*****************************************************  
;
VERIFY: PUSH    DX
        CALL    SET
        MOV     DX,HDATA        
        CMP     CX,0            ;IF CX HAS A # DO IT NOW
        JNE     V2
V1:     CMP     DI,0            ;ANY TO DO?
        JE      VDONE           ;EXIT IF NOT
        DEC     DI              ;DECREMENT IT NOW IN CASE OF ERROR
        XOR     CX,CX           ;MAX CX COUNT
V2:     IN      AL,DX           ;GET A BYTE
        CMP     AL,AH           ;WAS IT GOOD
        LOOPE   V2              ;LOOP UNTIL CX=0 OR AL<>AH
        JE      V1              ;IF ERROR QUIT, ELSE NEXT DI 
VDONE:  POP     DX              ;
        RET
;
;   CRLF - Print a carrage return followed by a line feed
;
CRLF2:  CALL    CRLF
CRLF:   MOV     CL,CR
        CALL    CONO
        MOV     CL,LF
        CALL    CONO
        RET

;
;**********************************************************
;
;   PRINT - Print a string terminated bye a '$' ( for CPM)
;
;           ENTRY - BX = Address of string terminated by a '$'
;
;           EXIT - BX = Address of end of string.
;
;**********************************************************
;
PRINT:  MOV     CL,ES:BYTE PTR [BX]
        CMP     CL,'$'
        JNE     PRNT2
        PUSH    BX ! PUSH DX ! PUSH ES
        MOV     CL,0BH                  ;CONSOLE STATUS
        INT     224
        POP ES ! POP DX ! POP BX
        OR      AL,AL
        JZ      PRNT1                   ;NO CHAR SO CONTINUE
        MOV     CL,1                    ;CLEAR INPUT BUFFER
        INT     224                     ;GET CHAR AND IGNORE
GOSYS:	MOV	CL,0
	INT	224			;IF ^C START OVER
PRNT1:  RET
PRNT2:  CALL    CONO
        INC     BX
        JMP     PRINT
;
;***********************************************
;
;       PRINT AN UNSIGNED NUMBER IN ASCII
;        ENTRY AX = NUMBER TO BE PRINTED
;              BX = BASE TO PRINT IN
;
;***********************************************
PUTN:   MOV     DX,0            ;PREPARE FOR DIVIDE 
        DIV     BX              ;PERFORM DIVIDE AND MODULO
        PUSH    DX              ;SAVE MODULO
        CMP     AX,0            ;TEST FOR DIGITS REMAINING
        JZ      PNUM            ;GO AND PRINT NUMBER
        CALL    PUTN            ;RECURSION TO DO REST OF NUMBER
PNUM:   POP     DX              ;GET REST OF BINARY DIGIT
        ADD     DL,'0'          ;ADD IN ASCII OFFSET
        CMP     DL,'9'+1        ;
        JC      PNDEC
        ADD     DL,'a'-'9'-1    ;MAKE HEX IF NEEDED
PNDEC:  PUSH    DX
        PUSH    AX
        MOV     CL,DL
        CALL    CONO
        POP     AX
        POP     DX
        RET                              
;*********************************************************
;
CYCCNT: MOV     AL,'9'
        PUSH    BX
        MOV     BX,OFFSET DIGIT1
        CMP     AL,[BX]
	JE	CARRY1
        INC     BYTE PTR [BX]           ;INCREMENT DIGIT1
        POP     BX
        RET
CARRY1:	MOV	BYTE PTR [BX],'0'	;ZERO DIGIT1
        INC     BX              ;DIGIT2 INTO HL
        CMP     AL,[BX]
	JE	CARRY2
        INC     BYTE PTR [BX]           ;INCREMENT DIGIT2
        POP     BX
        RET
CARRY2:	MOV	BYTE PTR [BX],'0'	;ZERO DIGIT2
        INC     BX              	;DIGIT2 INTO HL
        CMP     AL,BYTE PTR [BX]
	JE	ROLOVR
        INC     BYTE PTR [BX]           ;INCREMENT DIGIT3
        POP     BX
        RET
ROLOVR:	MOV	BYTE PTR [BX],'0'	;ZERO DIGIT3 
        POP     BX
        RET
;
;
SCORE:	PUSH	CX		;DONT MESS WITH REGISTER CX
	PUSH	BX		;SAVE BX
	PUSH	SI		;SAVE SI
	MOV	SI,OFFSET MSDFLG	;SI WILL POINT TO MSD FLAG
	MOV	BX,OFFSET DIGIT3	;HL HAS ADDRESS OF MSD
	CMP	BYTE PTR [BX],'0'	;IS MSD A AN ASCII '0'?
	JNE G1 ! JMP MSD0	;IF SO THEN JUMP TO FLAG SETTER
G1:
	MOV	BYTE PTR [SI],0	;ZERO FLAG
	MOV	CL,BYTE PTR [BX];MOST SIGNIFICANT DIGIT INTO C
	CALL	CONO		;OUTPUT DIRECTLY 
GDIG2:	DEC	BX		;HL HAS ADDRESS OF MIDDLE DIGIT
	CMP	BYTE PTR [BX],'0'		;MIDDLE DIGIT A ZERO?
	JNE G2 ! JMP FLGCHK	;IF SO SEE IF MSD ALSO A ZERO
G2:
PDIG2:	MOV	CL,BYTE PTR [BX]		;MIDDLE DIGIT INTO C REG
	CALL	CONO		;OUTPUT MIDDLE DIGIT
GDIG3:	DEC	BX		;GET LSD
	MOV	CL,BYTE PTR [BX]
	CALL	CONO		;OUTPUT LEAST SIGNIFICANT DIGIT
	POP	SI		;RESTORE SI
	POP	BX		;RESTORE BX
	POP	CX		;RESTORE REGISTER CX
	RET
;
;THIS ROUTINE IS REACHED ONLY IF MSD IS A '0'
;IT WILL SET THE MSD=ZERO FLAG AND SKIP AHEAD TO MIDDLE DIGIT
MSD0:
	MOV	BYTE PTR [SI],1	;SET THE MSD FLAG
	JMP	GDIG2		;DO NOT PRINT MSD BUT SKIP TO MIDDLE DIGIT
;
;THIS ROUTINE IS REACHED ONLY IF THE MIDDLE DIGIT IS A '0'
;IT WILL CHECK TO SEE WHETHER THE MSD WAS ALSO A ZERO AND IF
;SO WILL SKIP AHEAD TO THE LSD
;IF THE MSD IS NOT A ZERO IT WILL ALLOW THE MIDDLE DIGIT TO PRINT
;SI IS MSD FLAG ADDRESS
FLGCHK:
	CMP	BYTE PTR [SI],1	;IS MSD FLAG SET
	JZ	GDIG3		;IF FLAG SET SKIP TO LSD
	JMP	PDIG2		;SINCE MSD NOT A ZERO, PRINT MIDDLE DIGIT
;

;
;********************************************************* 
; CONO - Output a char to the console.
;
;     ENTRY - CL char to output
;**********************************************************
;
;	CompuPro Interfacer 3 support routines
;
GBI3	EQU	10h		;Interfacer 3 Base address
GBI3D	EQU	GBI3+0		;Uart data location
GBI3S	EQU	GBI3+1		;Uart status
GBI3M	EQU	GBI3+2		;Uart mode register
GBI3C	EQU	GBI3+3		;Uart command register
GBI3U	EQU	GBI3+7		;Uart select register

GBI3DV	EQU	00000010b	;Interfacer 3 Data Available
GBI3MT	EQU	00000001b	;Interfacer 3 Transmit Buffer Empty
GBI3DS	EQU	10000000b	;Interfacer 3 Data set ready
CON	EQU	0		;Interfacer 3 Console Select
PRN	EQU	4		;Interfacer 3 Printer Select
ULS	EQU	8		;Interfacer 3 User list 1 select

;
CONO:	
	IF	NOT CPM
	MOV	AL,CONUSR
	OUT	GBI3U,AL		;SELECT USER OF I/O 3
C1:	IN	GBI3S
	ANI	GBI3DS+GBI3MT		;
	SUI	GBI3DS+GBI3MT		;
	JNZ	C1			;LOOP UNTIL READY
	MOV	AL,CL
	AND	AL,#7FH			;STRIP HIGH BIT FOR PRINTER
	OUÔ	GBI3D
	ENDIF

	IF	CPM
	PUSH	BX ! PUSH DX ! PUSH ES
	MOV	DL,CL
	MOV	CL,2			;CONO FUNCTION
	INT	224
	POP ES	! POP DX ! POP BX
	ENDIF
	RET
;
	IF	NOT CPM
I4INIT:	MOV	AL,CONUSR
	OUT	GBI3U,AL
	MOV	AL,011101110B
	OUT	GBI3M,AL
	MOV	AL,01111110B		;9600 BAUD,
	OUT	GBI3M,AL
	MOV	AL,00100111B		;COMMAND
	OUT	GBI3C,AL
	RET
	ENDIF
;
CODEND:	
;*********************************************************
;   START OF EXTRA SEGMENT
;    This data will be in rom
;********************************************************
	IF CPM
	ESEG	
	ENDIF
	IF NOT CPM
	ORG	CODEND
	ENDIF
EXITS	DB	'BOARD # ','$'
YESEX	DB	' DOES EXIST.',CR,LF,'$'
NOEX	DB	' DOES NOT EXIST!!! I WILL SKIP IT.',CR,LF,'$'
TSTMSG	DB	CR,LF,'BEGINING TEST ON BOARD #','$'
	IF	CPM
OOMSG	DB	'  BIT STUCK HIGH, TESTING 00',CR,LF,'$'	
FFMSG	DB	'  BIT STUCK LOW, TESTING 0FFH',CR,LF,'$'
O55MSG	DB	'  CHECKERBOARD TEST (055H)',CR,LF,'$'
ADRMSG	DB	'  ADDRESS LINE TEST',CR,LF,'$'
RANDMSG	DB	'  RANDOM WRITE/READ TEST',CR,LF,'$'
	ENDIF
	IF	NOT CPM
OOMSG	DB	' 1 ',CR,'$'
FFMSG	DB	'    2 ',CR,'$'
055MSG	DB	'       3 ',CR,'$'
ADRMSG	DB	'          4 ',CR,'$'	
RANDMSG	DB	'             5,CR,LF,'$'
	ENDIF
PASSMSG	DB	' PASS NUMBER ','$'
DONMSG	DB	CR,LF,CR,LF,'DONE TESTING ALL BOARDS.'
	DB	' GIVE ALL BAD BOARDS A RED DOT!!!',CR,LF,'$'
ERR1MSG	DB	CR,LF,' ERROR - BYTE SHOULD BE ','$'
ERR2MSG	DB	' WAS ','$'
ERR3MSG	DB	'  AT ADDRESS ','$'
ERR4MSG	DB	' CHECK MEMORY CHIP AT ROW ','$'
ERR5MSG	DB	' COLUMN ','$'
;
NOMEMMS	DB	'  ERROR: UNABLE TO GET 4K MEMORY SEGMENT FROM CPM!!'
	DB	'  ADD MORE MEMORY TO SYSTEM. ',CR,LF,LF,'$'
CPYMSG	DB	'COPYRIGHT (C) COMPUPRO 1983.',CR,LF,'$'
;*********************************************************
;
; START OF DATA SEGMENT
;    This code will sit in unitialized RAM
;*********************************************************
	DSEG
	ORG	100H
F_BORD	RB	8
CURBORD	RB	1
ERRCNT	RB	1
DIGIT1	DB	'0'
DIGIT2	DB	'0'
DIGIT3	DB	'0'
MSDFLG	DB	0
	IF	CPM
MCB	DW	0,0
	DB	0	
SAVBUF	RW	(4 * 1024) / 2	;RESERVE 4K BYTES
	ENDIF
ESSEG:
	DB	0
;
;*********************************************************
;   STACK SEGMENT
; IN NON CPM VERSION STACK SEGMENT WILL BE SET WITH CODE
;
STKSEG:
	DB	0	;LET STACK SEG BEGIN HERE FOR ROM VERSION 
	SSEG
	RS	128
	DB	0
	IF NOT CPM
	ORG	0FFFF0H	;RESET VECTOR FOR 8086	
	JMPF	0F0000H ;JUMP TO START OF CODE
	ENDIF
	END

