.title	"Test network diagnostic program"
	.sbttl	"TESTNET"
;----------
; Test the network
;
version ==	1
revision==	1
;       
        .phex
	.pabs
	.loc	100h
	lxi	sp,stack ;stack at end of program
;---------------
; Update history
;
; 1.0	Initial program written by Doug Brentlinger
;				and Peter Kavaler
;
; 1.1  	Code shortened and optimized. 11/15/81 Doug
;	Scope reports (through parallel port) added.
;	Additional user commands initiated.
;				    11/27/81 D Stein
;---------------
; Test to see if this is a user station.  If it is,
; turn off the pole acknowledgments.
	lda	47h	;user number
	ora	A	;if user number = 0, this
   	jz	0	;is a master station no go
	cpi	0ffh	;if user station, turn off
	cnz	nackpoll;poll acknowledgment
;---------------
        mvi	A,0	  
	sta	dskflg	  ; reset disk write flag
	call	stoMAPbyt ; Save current disk select
;
; Ask the user whether he/she wants to store errors on
; the disk. If yes, ask which one and initialize it.
;
        lxi	H,crlf	  ; space down a line.
	call	prtmsg
dskask:	lxi	H,savedsk ; Do you want to save the
	call	prtmsg	  ; errors on disk
	call	CONIN
	sta	saveER	  ; user's response saved
	cpi	'Y'	  ; write=yes?
	jrz	findED	  ; Write=yes. Find error disk
	cpi	'N'	   
	jz	START	  
	lxi	H,errmsg  ; bad entry. ask again
	call	prtmsg
	jmpr	dskask
.page
; User wants errors saved on disk. Which disk ?
findED:	lxi	H,dskmsg  ; use A,B,C, or D to
	call	prtmsg	  ; save errors?
	call	getCPMdsk
	sta	ERRDSK	  ; disk for holding errs
	mov	C,A
	call	SELDSK	  ; select disk 1st thru BIOS
	call	stoMAPbyt ; Save this MAP byte.
;--------------
; Kill,create,open,write, and close the file.
	lxi	H,waitmsg
	call	prtmsg	  ; Tell user to wait.
	lda	ERRDSK	  ; get the disk from above and
	mov	E,A	  ; load it in E
	mvi	C,logdsk  ; CP/M 14 Select Disk
	call	BDOS	  ; select D disk thru BDOS
	mvi	C,kill	  ; CP/M 19 Delete File
	lxi 	D,FCB  	  ; File Control Block addr
	call	BDOS	  ; kill the file CONFILE.TXT
	mvi	C,create  ; CP/M 22 Make File
	lxi 	D,FCB  	  ; File Control Block addr
	call	BDOS	  ; create and open the file
	mvi	C,setdma  ; CP/M 26 Set DMA Address
	lxi	D,hdfile  ; file header addr
	call	BDOS        
	mvi	C,wnr	  ; CP/M 21 Write Sequential
	lxi 	D,FCB  	  ; File Control Block addr
	call	BDOS	  ; write a file header
	mvi	C,setdma  ; CP/M 26 Set DMA Address
	lxi	D,hdfil1  ; file header addr
	call	BDOS        
	mvi	C,wnr	  ; CP/M 21 Write Sequential
	lxi 	D,FCB  	  ; File Control Block addr
	call	BDOS	  ; write a file header
	lxi	H,dskerr  ; error message
	cpi	0	  ; returned by BDOS if error
	push	PSW
	cnz	prtmsg	  ; print err msg
	pop	PSW
	jnz	0	  ; Wboot if can't write
	mvi	C,close   ; CP/M 16 Close File
	lxi 	D,FCB  	  ; File Control Block addr
	call	BDOS	  ; close the file
	mvi	C,setdma  ; CP/M 26 Set DMA Address
	lxi	D,80h	  
	call	BDOS	  ; reset the dma
	lxi	H,dskbuf
	shld	bufchr	  ; begin disk buffer
	mvi	A,0
	sta	bufcnt	  ; zero the counter
	mvi	A,0FFh
	sta	dskflg	  ; set the disk write flag
.page
.sbttl "START"
;---------------
; First determine if we have a master or user station.
;
START:
..1:    lxi	h,crlf	;space one line
	call 	prtmsg
	lxi	h,massta 	 
	call    prtmsg	;print a message
	call	CONIN	;get the response
	cpi	'Y'    	;is this the master
	jrz   	master 	;yes? do the master
	cpi	'N'	;is this the station
	jrz	station	;yes? do the station
	lxi     h,crlf                 
	call    prtmsg  ;space one line
	lxi	h,errmsg ;user error print   
	call 	prtmsg	;error message
	jmpr	..1     ;and try again
;-------------
;The operator is on the master terminal
;
MASTER:
        lxi     h,crlf  
	call	prtmsg  ;spaced one line
	lxi	h,mastmsg	 
	call	prtmsg  ;print the master msg
        call    CONIN   ;get the users response
	sui     '0'     ;convert number to hex
	sta     maxstatn ;max number of user stations
	call    chkchtr ;check the response
	cpi	0	;master response is incorrect
	jrz	MASTER	;so try again
	lxi	H,HELPmsg  ;user response ok
	call	prtmsg	   ;print instructions
	jmp     bgnmastest ;and start the test
;---------------
;otherwise, we have a station
;
STATION:
    	lxi	h,crlf
	call	prtmsg  ;space one line
Š	lxi	h,usermsg
	call    prtmsg  ;enter user number 
        call    CONIN   ;receive user response
	sui     '0'     ;convert ascii to hex
	sta     stanbr  ;station number
	call    chkchtr ;check user response
	cpi     0	;error in response of
	jrz     STATION ;the user,try again
	lxi	H,HELPmsg
	call	prtmsg	; print instructions

.page
.sbttl "USER LOOP"
;--------------
; This code controls the user station receive send. 
;
..again:
	CALL	CHEKCON	   ;check for user commands
	lxi	H,lopmsg
	call    prtmsg	   ;print the loop message
        call	prtloop    ;print the loop count
	lxi     H,bgn1msg  ;inform user we are 
	call	prtmsg	   ;starting 1 byte test 
	lxi	B,byt1length
	sbcd	bytlength  ;used in receive send
        call    cntRS      ;user receive
	cpi     '/'	   ;if accum has a /, start
	jrz	..again    ;the program over
	lxi     H,bgn16msg ;inform user we are 
        call	prtmsg	   ;starting 16 byte test 
	lxi	B,byt16length
	sbcd	bytlength  ;used in receive send
	call    cntRS      ;and send counters
	cpi     '/'	   ;if accum has a /, start
	jrz	..again    ;the program over
	lxi     H,bgn28msg ;inform user we are 
	call	prtmsg	   ;starting 128 byte test 
	lxi	B,byt28length
	sbcd	bytlength  ;used in receive send
	call    cntRS    
	cpi	'/'	   ;if accum has a /, start
	jrz	..again    ;the program over
	lxi     H,bgn24msg ;inform user we are 
	call	prtmsg	   ;starting 1024 byte test 
	lxi	B,byt24length
	sbcd	bytlength  ;used in receive send
	call    cntRS  
	cpi     '/'	   ;if accum has a /, start
	jrz	..again    ;the program over
	lbcd    loopcntr   
	inx     B	   ;add one to loop counter for
	sbcd	loopcntr   ;summary and store it 
	jmpr    ..again
.page
.sbttl "MASTER LOOP"
;---------------
; This is the start of the 1 byte HiNet test
;
bgnmastst:
	lxi	B,byt1length ;length of send
	sbcd	bytlength ;length of send in storage
	lxi	H,lopmsg
	call    prtmsg	;print the loop message
	call	prtloop ;print the loop count
        lxi     H,bgn1msg ;inform master we are 
	call	prtmsg	;starting 1 byte test 
        lxi     H,SRbuff;addr of buffer
	mvi     M,00    ;fill buffer with 00's
	call	cntSR	;send and receive pattern
	cpi     '/'	;if accum has a /, start
	jrz	bgnmastst;the program over
	mvi     A,'.'	;print a period for
	call    conslout;each test loop 
	lxi     H,SRbuff;addr of buffer
	mvi     M,0FFh  ;fill buffer with FF's
	call	cntSR	;send and receive pattern
	mvi     A,'.'	;print a period for
	call    conslout;each test loop 
	lxi     H,SRbuff;addr of buffer
	mvi     M,0E5h  ;fill buffer with E5's
	call	cntSR	;send and receive pattern
	cpi     '/'	;if accum has a /, start
	jrz	bgnmastst;the program over
	mvi     A,'.'	;print a period for
	call    conslout;each test loop 
;---------------
; This is the start of the 16 byte HiNet test
	lxi	B,byt16length ;length of send
	sbcd	bytlength  ;length of send in storage
	lxi     H,bgn16msg ;inform master we are 
	call	prtmsg	 ;starting 16 byte test 
        call	makran  ;fill with random pattern
	call	cntSR	;send and receive pattern
	cpi     '/'	;if accum has a /, start
	jz	bgnmastst;the program over
	mvi     A,'.'	;print a period for
	call    conslout;each test loop 
	call    makfix  ;fill with fixed pattern
	call	cntSR	;send and receive pattern
	mvi     A,'.'	;print a period for
	call    conslout;each test loop 
	call	maklin  ;fill with lineal pattern
	call	cntSR	;send and receive pattern
	cpi     '/'	;if accum has a /, start
	jz	bgnmastst;the program over
	mvi     A,'.'	;print a period for
	call    conslout;each test loop 
.page
;---------------
; This is the start of the 128 byte HiNet test.
	lxi	B,byt28length ;length of send
	sbcd	bytlength  ;length of send in storage
	lxi     H,bgn28msg ;inform master we are 
	call	prtmsg	 ;starting 128 byte test 
        call	makran  ;fill with random pattern
	call	cntSR	;send and receive pattern
	cpi     '/'	;if accum has a /, start
	jz	bgnmastst;the program over
	mvi     A,'.'	;print a period for
	call    conslout;each test loop 
	call    makfix  ;fill with fixed pattern
	call	cntSR	;send and receive pattern
	mvi     A,'.'	;print a period for
	call    conslout;each test loop 
	call	maklin  ;fill with lineal pattern
	call	cntSR	;send and receive pattern
	cpi     '/'	;if accum has a /, start
	jz	bgnmastst;the program over
	mvi     A,'.'	;print a period for
	call    conslout;each test loop 
;
;---------------  
;This the start of the 1024 byte HiNet test.
;
	lxi	B,byt24length ;length of send
	sbcd	bytlength ;length of send in storage
	lxi     H,bgn24msg ;inform master we are 
	call	prtmsg	;starting 1024 byte test 
        call	makran  ;fill with random pattern
	call	cntSR	;send and receive pattern
	cpi     '/'	;if accum has a /, start
	jz	bgnmastst;the program over
	mvi     A,'.'	;print a period for
	call    conslout;each test loop 
	call    makfix  ;fill with fixed pattern
	call	cntSR	;send and receive pattern
	cpi     '/'	;if accum has a /, start
	jz	bgnmastst;the program over
	mvi     A,'.'	;print a period for
	call    conslout;each test loop 
	call	maklin  ;fill with lineal pattern
	call	cntSR	;send and receive pattern
	cpi     '/'	;if accum has a /, start
	jz	bgnmastst;the program over
	mvi     A,'.'	;print a period for
	call    conslout;each test loop 
	lbcd    loopcntr   
	inx     B	   ;add one to loop counter for
	sbcd	loopcntr   ;summary and store it 
     	jmp     bgnmastest
.page
.sbttl "SUBROUTINES"
;           -------------
;            SUBROUTINES
;           -------------
;
; subroutine chkchtr: check the reponse of the user
;
; reg in:  A
; reg out: A
; reg destroyed: A
;
chkchtr:
        cpi     1       ;stop 0 and all 
	jrc     ..3     ;garbage responses
	cpi     maxusr+1 ;tests for > max
	jrnc    ..3     ;number of users 
	lxi     H,crlf  ;space a line
	call    prtmsg
    	lxi	h,strtmsg ;operator can begin
	calì    prtmsç  ;prinô message
	call    waitCR  ;wait for CR from user
	mvi     A,1     ;accum is 1 for test       
	ret 		;correct user response
..3:    lxi 	H,crlf  ;space one line
	call    prtmsg
        lxi	h,error2 ;operator entered 0 or
	call	prtmsg  ;too many stations  
	mvi     A,0   	;accum is 0 for test
	ret		;start over 
;---------------
; subroutine prtloop: print the loop count 
;
; reg in:  HL
; reg out: None
; reg destroyed: None
prtloop:
        lhld	loopcntr;counts the loops completed
	call	cvthlbcd;convert hex to decimal
	push	D
	mov	A,D
	call	prtby2	;print next numbers with zeros
	pop	D
	mov	A,E
	call	prtby2  ;print the last numbers
	ret
.page
.sbttl "MASTER SEND REC"
;---------------
; subroutine: count the HiNet MASTER send and 
;             receives 
cntSR:
; reg in:  A
; reg out: None
; reg destroyed: None
;
..loop: lda	timcntr
	dcr	A
	sta 	timcntr
	cpi	0
	cz	masreinit 
	cpi     '/'	   ;if accum has a /, 
	jrz     ..exit     ;return to main program
	mvi	A,1	   ;bit to be changed up
	call	upbit	   ;before send is started
        lxi	H,SRbuff   ;send rec buffer 
	lbcd    bytlength  ;byte length 
	mvi	E,$halfms  ;maximum time for send
	lda	stanbr     ;user number
	call    SENDNET
	mvi	A,1	   ;bit to be changed down
	call	downbit	   ;after send is finished
	mvi	A,0	   ;bit to be changed up
	call	upbit	   ;before receive is started
	lxi	H,RECbuff  ;response from user buffer
	lbcd	bytlength  ;byte length
	lxi     D,$1sec    ;maximum time for rec  
	lda	stanbr     ;user number
	call	RECNET
	push	PSW	   ;save the accum
	call    testbit    ;test the receive net bits
	pop	PSW	   ;get it back and test the
	bit	7,A	   ;time out bit. If we timed
	jrz	..loop	   ;out, start over  
	mvi	A,0	   ;bit to be changed down
	call	downbit	   ;after receive is finished
.page
 	mvi	A,inittim  ;the # of timeouts allowed
	sta	timcntr	   ;stored in the counter
    	lda     stanbr     ;station number in accum
	inr     A 
	sta     stanbr     ;store the accum contents
	mov	B,A        ;accum in reg B
	lda     maxstatn   ;max stations in accum
	cmp	B          ;is this the last user?
	jrnc    ..loop     ;no, send for next station
	mvi     A,1	   ;yes, reinitialize counter
	sta     stanbr     ;station number = 1
        lbcd    mascntr    
	dcx     B          ;sub one from the counter
	sbcd    mascntr 
	mov     A,C        ;final send and receive?
	ora     B
	jrnz    ..loop     ;no, send and receive again
..exit: lbcd    tstloop    ;re-initialize the counter
	sbcd    mascntr    ;store it and return
   	ret
.page
.sbttl "TESTS"
;----------------
; Subroutine testbit:  Test the receive net bits 
;                      for errors
; reg in:  A
; reg out: None
; reg destroyed: A
testbit:
	bit	7,A
	jrnz    ..1       ;don't print error message
	mvi	A,2	  ;bit to be changed up
	call	upbit	  ;when timeout is determined
	lbcd	errcntr
	inx	B	  ;add 1 to the error counter
	sbcd	errcntr	  ;and store it
	call	chekcon	  ;user wants something?
	lda     stanbr
        call    prtbyt    ;print user number before 'T'
        mvi     C,'T'	  ;print a 'T' if
	call    charout   ;HiNet times out
	mvi	A,2	  ;bit to be changed down when
	call 	downbit	  ;timeout processing is done
	ret               ;return
..1:    bit	6,A	  ;if bit 6 is 0, no CRC error
	jrz     ..2       ;so compare the buffers
	lbcd	errcntr
	inx	B	  ;add 1 to the error counter
	sbcd	errcntr	  ;and store it
	lda     stanbr
        call    prtbyt    ;print user number before 'T'
        mvi     C,'C'	  ;print a 'C' for
	call    charout   ;CRC error
..2:    call    compbuff  ;last chance to compare buffs
	call    chekcon	  ;user wants something?
	ret
.page
.sbttl "USER SEND REC"
;--------------
; subroutine: count the HiNet STATION receive and
;	      send for the HiNet tests
cntRS:
;
..loop: lda	timcntr
	dcr	A
	sta 	timcntr
	cpi	0
	cz	usrreinit 
	cpi     '/'	  ;if accum has a /, 
	jz      ..exit    ;return to main program
	mvi	A,0	  ;bit to be changed up
	call	upbit	  ;when receive starts
       	lxi	H,SRbuff  ;receive send buffer
	lbcd    bytlength
	lxi     D,$1sec   ;maximum time for rec  
	lda	stanbr    ;user number
	call	RECNET
	bit	7,A
	jrnz    ..1       ;don't print error message
	mvi	A,2	  ;bit to be changed
	call 	upbit	  ;to be changed up
        mvi     A,'T'     ;for time out
	call    conslout  ;HiNet times out
	lbcd	errcntr
	inx	B	  ;add 1 to the error counter
	sbcd	errcntr	  ;and store it
	mvi	A,2	  ;bit to be changed down when
	call	downbit	  ;timeout processing is done
	jmpr    ..loop    ;don't send without receive
..1:    bit	6,A
	jrz	..2
	mvi	A,'C'
	call    conslout
	lbcd	errcntr
	inx	B	  ;add 1 to the error counter
	sbcd	errcntr	  ;and store it
	mvi	A,0	  ;bit to be changed down
	call	downbit	  ;when the receive is done
	mvi	A,1	  ;bit to be changed up
	call	upbit	  ;when sene begins
..2:    lxi	H,SRbuff  ;receive send buffer 
	lbcd    bytlength ;byte length 
	mvi	E,$halfms ;maximum time for send
	lda	stanbr    ;user number
	call	SENDNET
	mvi	A,1	  ;bit to be changed down
	call	downbit	  ;when send finishes
.page
	mvi	A,inittim ;the # of timeouts allowed
	sta	timcntr	  ;stored in the counter
	lbcd    usrcntr 
	dcx     B   	  ;decrement the user counter
	sbcd    usrcntr   ;store the counter
	mov     A,C        
	ora     B
	jnz     ..loop    ;no, send and receive again
	lbcd    tstloop   ;re-initialize the counter,
	sbcd    usrcntr   ;store it and return
	mvi     A,'.'     ;print a period for
	call    conslout  ;each test loop 
	lda     dotcntr
	dcr     A	  ;load, decrement and 
	sta     dotcntr   ;store dot counter
	cpi     0	  ;have we done 3 loops?
	jnz     ..loop	  ;no, do another loop
	mvi     A,3       ;yes,
	sta     dotcntr   ;re-initialize dot counter
..exit:	ret		  ;and return to main program
.page
.sbttl "FILL BUFFERS"
; HiNet I/O buffer pattern subroutines
;
; Create a random buffer at SRbuff (2000h).
; This buffer will be used for writing each block
; to the HiNet.
makran:
	lxi 	H,SRbuff	; HL= write buffer addr
	lbcd    bytlength	; BC= num bytes to fill
..ranfil:
	call	MAKERAN		; A = randomized number
	mov	M,A		; number is now in buf
	inx	H		; next buffer address
	dcx	B		; decrement byte count
	mov	A,B	
	ora	C		; B=C=0 ?
	jrnz	..ranfil 	; keep filling buffer
	ret
;-------------
; Create a linear buffer at SRbuff (2000h).
;This buffer will be used for writing each block
;to the HiNet. 
makLIN:
	lxi     H,SRbuff	; HL= write buff addr
	lbcd    bytlength	; BC= num bytes to fill
	mvi	D,0		; D holds linear number
..linfil:
	mov	M,D		; number is now in buf
	inr	D		; next linear number
	inx	H		; next buffer address
	dcx	B		; decrement byte count
	mov	A,B	
	ora	C		; B=C=0 ?
	jrnz	..linfil	; keep filling buffer
	ret
;----------
; Create a fixed buffer at SRbuff (2000h).
;This buffer will be used for writing each block
;to the HiNet. 
makFIX:
	lxi	H,SRbuff	; HL= write buf addr
	lbcd    bytlength	; BC= num bytes to fill
..fixfil:
	lda	fixbyt
	mov	M,A		; number is now in buf
	inx	H		; next buffer address
	dcx	B		; decrement byte count
	mov	A,B	
	ora	C		; B=C=0 ?
	jrnz	..fixfil	; keep filling buffer
	ret
.page
.sbttl "REINITIALIZE"
;Subroutine masreinit: Reinitialize the master counters.
;	               Delay the master so the user 
;		       will be ready to receive the 
;                      1 byte send.
; Reg in:
; Reg out: A
; Destroyed: None
;
masreinit:
	lxi	H,dlaymsg
	call	prtmsg	;let user know of delay
..1:	lxi	D,$1sec	;the time delay
..2:	dcx	D	;less one
	mov	A,E	
	ora	D
	jrnz	..2	;if not 0, loop again
	lda	delaymas 
	dcr	A
	sta	delaymas
	cpi	0	;do it all 100 times for a 
	jrnz	..1	;12 second delay
	mvi	A,140   ;reinit delaymas
	sta	delaymas
	mvi	A,1
	sta	stanbr	 ;back to first station
        mvi	A,inittim;the # of timeouts allowed
	sta	timcntr  ;reinit the time counter
	mvi	A,'/'	 ;test character
	ret
;---------------
; Subroutine usrreinit: Reinitialize the user counters
; Reg in:
; Reg out: A
; Destroyed: None
;
usrreinit:
   	lbcd	tstloop	 ;number of loops
	sbcd	usrcntr  ;to user counter
	mvi     A,3   
	sta     dotcntr  ;re-initialize dot counter
        mvi	A,inittim;the # of timeouts allowed
	sta	timcntr  ;reinit the time counter
	mvi	A,'/'	 ;test character
	ret
.page
.sbttl "SUBROUTINES"
;----------
; Subroutine: compbuff: compare HiNet send and receive
;		        buffers. Letter 'B' indicates
;        		the buffers do not match
; Regs  in:	BC
; Regs out:	None
; Regs destroyed: BC
;
COMPBUFF:
	lbcd	bytlength ;used for buffer compare
	lxi	H,SRbuff  ;the Hinet send-rec buffer
	lxi     D,RECbuff ;the master receive buffer
..loop:	ldax	D	;RECbuff in the accum
	cmp	M	;SRbuff is in memory
	jrnz	..error ;not =, do error routine
       	dcx	B
	mov	A,B
	ora	C	;if bytlength = 0, return
	rz		
        inx	H	;next byte, send rec buffer
	inx	D	;next byte, receive buffer
	jmpr    ..loop  ;test the next byte
..error:
	lbcd	errcntr
	inx	B	;add 1 to the error counter
	sbcd	errcntr	;and store it
	lda     stanbr
        call    prtbyt  ;print user number before 'B'
        mvi     C,'D'	;print a 'D' if
	call    charout ;HiNet times out
	ret		;return
;---------------
; print char in C (using BDOS)
;
CHAROUT:
	lda	saveER
	cpi	'Y'     ;if Y, store the errors on
	jrnz    ..1     ;disk, otherwise, jump
	call    stobyt  ;store error on disk
	push    B	;save the error character
	lda     stanbr
	aci	'0'     ;convert to ascii
	mov     C,A 
	call    stobyt	;store user number on disk
	pop	B	;get the error back
..1:	push	PSW	; save A
	mov	E,C	; char is in C
	mvi	C,2	; command 2
	call	BDOS	; print the char
	pop	PSW	; get A back
	ret		; thats all
.page
;---------------
; Subroutine: 	MAKERAN
; Regs in:	none
; Regs out:	A = pseudo-random number
; Generate a pseudo-random byte based on the
;previous byte.
MAKERAN:
	lda	..lastran
	adi	31
	xri	11010001b
	rrc
	sta	..lastran
	ret
..lastran:
	.byte	123
;----------------
; Print a message on the console
;
;  Regs in:   HL = address of string (ended by null)
;  Regs out:  none
;  Destroyed: A, HL
prtmsg:
	mov	A,M
	ora	A
	rz
	call	conslout
	inx	H
	jmpr	prtmsg
;---------------
; Print a character on the console
;  Regs in:   A = character to be printed
conslout:
	push	H
	push	D
	push	B
	mvi	C,2
	mov	E,A
	call	5	; print using BDOS
	pop	B
	pop	D
	pop	H
	ret
.page
;---------------
; Print a byte on the console
;  Regs in:   A = byte to be printed
;  Regs out:  none
;  Destroyed: A
prtbyt:
	push	PSW
	rrc
	rrc
	rrc
	rrc
	ani	0Fh	
	jrz	..1	; dont print leading zeros
	call	prtnbl
..1:	pop	PSW
prtnbl:	ani	0Fh
	adi	'0'
	cpi	'9'+1
	jrc     conslout
	adi	'A'-('9'+1)
	jmpr	conslout

;---------------
; Print a byte on the console
;  (print blanks instead of leading zeros)
;  Regs in:   A = byte to be printed
;  Regs out:  none
;  Destroyed: A
prtby1:
	push	PSW
	rrc
	rrc
	rrc
	rrc
	ani	0Fh	
	jrz	..prtblk
	call	..prtnbl
	pop	PSW
..prtnbl:ani	0Fh
	adi	'0'
	cpi	'9'+1
	jrc	conslout
	adi	'A'-('9'+1)
	jmpr	conslout
..prtblk:mvi	A,' '
	call	conslout
	pop	PSW
	ani	0Fh
	jrnz	prtnbl
	mvi	A,' '
	mov	C,A
	jmpr	conslout
.page
;---------------
; Print a byte on the console
;  (Do print leading zeros)
;  Regs in:   A = byte to be printed
;  Regs out:  none
;  Destroyed: A
prtby2:
	push	PSW
	rrc
	rrc
	rrc
	rrc
	ani	0Fh	
	call	..prtnbl
	pop	PSW
..prtnbl:ani	0Fh
	adi	'0'
	cpi	'9'+1
	jrc	conslout
	adi	'A'-('9'+1)
	jmpr	conslout
;---------
; get character from console (using BDOS) then
; convert lower to upper case.
; Abort on CTRL-C, restart on ESC
CONIN:
	mvi	C,1	; command 1
	call	BDOS	; read a char
	cpi	ctrlC
	jz	0	; abort if ctrlC
	cpi	1Bh
	jrz	..DDT	; jump into DDT if ESC
	call	CVTluc	; convert to upper case
	ret		; and return
..DDT:	rst	6	
;-------------------
; CVTLUC:  used to convert lower case on the CRT
;	   to upper case  
;
CVTluc:	cpi	'a'	; convert upper to lower case
	jm	..up
	cpi	'z'+1
	jp	..up	
	sui	'a'-'A'
..up:	ret
.page
;---------------
;  Subroutine chekcon:  Check the console for a
;			character
;  Reg in: A
;  Reg out: None
;  Destroyed: A
Chekcon:
	mvi 	C,constat ;CP/M 11 Get Console Status
	call    BDOS    ;If accum = FF, there is a
	rrc         	;character so see if it is
	rnc	 	;valid
	call	conin
	cpi	'W'
	jrz	..Wcmd	;character is a 'W' so wait.
        cpi     'S'	;character is an 
	jrz	..Scmd	;'S' for Summary
	cpi	'F'	;character is an 'F' for 
	jrz	Fcmd	;finish the program
	lxi	H,HELPmsg;Character is unrecognized,
	call	prtmsg	;so print the help message
	ret		;and return.
..Wcmd:			;wait command 
        lxi	H,RESTmsg
	call	prtmsg	;Print 'waiting' message.
	mvi	C,constat;CP/M 11, Check Console Status
	call	BDOS
	rrc
	jrc	..Wcmd	;loop until character recvd
	call	conin	;read the irrelevant char
	ret		;and return.
..Scmd: 		;summary command
        lxi	H,summsg
	call	prtmsg	;print the summary message
	lxi	H,cntrmsg
	call    prtmsg	;print the error message
	lhld	errcntr ;counts the errors detected
	call	cvthlbcd;convert hex to decimal
	pusè	D	;savå thå registers
	mov	A,C
	call	prtnbl	;print the first byte
	pop	D
	push	D
	mov	C,D	
	mov	A,D
	call	prtby2	;print next numbers with zeros
	pop	D
	mov	A,E
	call	prtby2  ;print the last numbers
.page
	lxi	H,loopmsg
	call    prtmsg	;print the loop message
        lhld	loopcntr;counts the loops completed
	call	cvthlbcd;convert hex to decimal
	push	D
	mov	A,D
	call	prtby2	;print next numbers with zeros
	pop	D
	mov	A,E
	call	prtby2  ;print the last numbers
	lxi	H,undlin
	call	prtmsg  ;underline the summary
	ret	
Fcmd:   		;finish command
	lda	saveER	;if you did not specify a 
	cpi	'Y'	;disk, you can not finish
	jrnz	..exit	;this way
..1:    lhld	bufchr	;error buffer address
	mvi	m,'F'   ;put an 'F' in the buffer
	inx	H	;next buffer addr
	shld	bufchr	;store it
	lda	bufcnt	;how many do we have?
	inr	A	;plus one
	cpi     128	;128?
	sta	bufcnt  ;store it
	jrnz    ..1	;no, pad it some more
    	call	diskit	;yes, write the buffer
	lxi	H,crlf
	call    prtmsg	;space one line
	lxi	H,Ferrmsg;if 'F' was an error
	call	prtmsg	;here is how to save it
	jmp	0	;FINISHED
..exit: lxi	H,crlf
	call	prtmsg	;space one line
        lxi	H,nodskmsg;no disk to store buffer
	call	prtmsg	;on so return to program
	ret
.page
;---------------
; Wait for a cr to be typed
;
waitCR:
       	call	PRTMSG	; print message
..loop:	call	CONIN	; read a char
	cpi	cr	; loop if not cr
	jrnz	..loop
	ret		; return if cr
;---------------
; Subroutine:	cvtHLbcd
; Regs  in:	HL = word to be converted to BCD
; Regs out:	C,D,E = three bytes in BCD format
;Destroyed:	A,HL
;Convert a register pair's contents to BCD
cvtHLbcd:
	lxi	D,00
	lxi	B,00
..tst:	mov	A,H	; HL is our hex counter
	ora	A
	jrnz	..addBCD
	ora	L	; Does HL=0
	rz		; we finished decrementing HL
..addBCD:
	dcx	H	; reduce hex count
	mov	A,E	; now increment decimal count
	adi	1
	daa
	mov	E,A	; put low BCD back byte in E
	jrnc	..tst	; decrement, test again.
	mov	A,D	; Since carry was set
	adi	1	; Increment next BCD byte.
	daa
	mov	D,A	; put high BCD back byte in D
	jrnc	..tst	; decrement, test again.
	mov	A,C	; Since carry was set
	adi	1	; Increment next BCD byte.
	daa
	mov	C,A	; put Meg BCD byte back in C
	jmpr	..tst	; decrement, test again.
.page
.sbttl "NET ROUTINES"
;---------------
; Transmit a block on the network
;  Regs in:   HL = block address
;   	      BC = byte count
;	      E  = delay time before transmitting
;	      A  = user number
;  Regs out:  none
;  Destroyed: A, BC, DE, HL
SENDNET: 
	inr	E	; delay so that receiver has
..delay:dcr	E	; time to prepare for message
	jrnz	..delay	
	mov	D,A	; save user number
	shld	DMANSadr; store block address
	dcx	B	; DMA chip wants real size - 1
	sbcd	DMANSsize
	mov	A,C
	ora	B
	jrz	..send1
;
; Send more than one byte
	push	D
	lhld	1
	lxi	D,DMAvect
	dad	D
        lxi	D,DMATdone; setup the DMA vector
	mov	M,E
	inx	H
	mov	M,D	;store the DMA vector
	pop	D
	mvi	A,1	; multiplex SIO1B to DMA
	out	PIOAD
	lxi	H,DMANSprog; program the DMA chip
	lxi	B,DMAN$<8+DMA
	outir
	lxi	H,SENDprog
	lxi	B,SEND$<8+SIO1BC
	outir
	mvi	B,9	; force min 3 leading flags
	djnz	.
	mov	A,D
	di
	out	SIO1BD	; send user number
	mvi	A,87h	; enable the DMA chip
	out	DMA
	mvi	A,11010000b; reset underrun/EOM status
	out	SIO1BC
	jmpr	..fin
.page
;
; Send one byte (DMA chip isn't needed)
..send1:
	lxi	H,SENDprog
	lxi	B,SEND$<8+SIO1BC
	outir
	mvi	B,9	; force min 3 leading flags
	djnz	.
	lbcd	DMANSadr
	ldax	B
	mov	E,A	; get message byte
	mvi	C,SIO1BD
	di
	outp	D	; send userno
	mvi	A,11010000b; reset underrun/EOM status
	out	SIO1BC	; reset underrun status
..3:	in	SIO1BC
	bit	2,A	; wait for transmitter empty
	jrz	..3
	outp	E	; send message byte
;
; Handle the end of the transmission
..fin:	ei
..4:	in	SIO1BC	; wait for transmit underrun
	bit	6,A
	jrz	..4
..5:	in	SIO1BC	; wait for CRC complete
	bit	2,A
	jrz	..5
	mvi	B,10h	; force min 3 closing flags
	djnz	.
	mvi	A,18h
	out	SIO1BC	; reset the SIO chip
	ret
.page
;----------
; Receive a block from the network
;  Regs in:   HL = block address
;	      BC = maximum byte count
;	      DE = timeout count
;	      A  = user number
;  Regs out:  A  = error status
;		   bit 7 = end of frame (0 if time-out)
;		   bit 6 = CRC error
;		   bit 5 = receiver overrun
;  Destroyed: A, BC, DE, HL
RECNET:
	push	D	; save the timeout count
	call	RECbegin; program the SIO chip
	pop	D	; get the timeout count back
	ei		; make sure SIO can interrupt
	lxi	H,RECstat; point to receiver status
	mvi	M,1	; tell REClast to not ack polls
; Wait for block received from network cable
..wait:	mvi	B,8	; inner loop count
..loop:	mov	A,M	; check receiver status
	bit	4,A
	rnz		; return if block received
	djnz	..loop
	dcx	D	; decrement timeout count
	mov	A,E
	ora	D
	jrnz	..wait	; fall through if timeout
	call	REClast	; pretend we received a block
	sub	A	; return "timeout" status
	ret
; Program the SIO chip to receive a block
RECbegin:
	sta	RECadr	; station address
	shld	DMANRadr; DMA address
	dcx	B	
	sbcd	DMANRsize; DMA length = real length-1
	mov	A,C
	ora	B
	jrz	..prog
; Receive more than one byte
	lhld	1
	lxi	D,DMAvect
	dad	D
        lxi	D,DMARdone; setup the DMA vector
	mov	M,E
	inx	H
	mov	M,D	;store the DMA vector
	mvi	A,1	; multiplex SIO1B to DMA
	out	PIOAD
	lxi	H,DMANRprog; program the DMA chip
	lxi	B,DMAN$<8+DMA
	outir
.page
..prog:	lhld	1
	lxi	D,SIO1vect+4
	dad	D
        lxi	D,RECfirst; setup the DMA vector
	mov	M,E
	inx	H
	mov	M,D	  ;store the DMA vector
	lhld	1
	lxi	D,SIO1vect+6
	dad	D
        lxi	D,REClast ;setup the DMA vector
	mov	M,E
	inx	H
	mov	M,D	  ;store the DMA vector
	lxi	H,RECprog; program the SIO chip
	lxi	B,REC$<8+SIO1BC
	outir
	ei		; make sure interrupts enabled
	ret
;---------------
; Receive status and count, and temp storage for regs
RECstat:.byte	0FFh	; receiver status
REC.SP:	.word	0
REC.HL:	.word	0
	.byte	76h,76h,76h,76h,76h,76h,76h,76h
	.byte	76h,76h,76h,76h,76h,76h,76h,76h
	.byte	76h,76h,76h,76h,76h,76h,76h,76h
RECstck:
;---------------
; SDLC receive interrupt on first char
RECfirst:
	push	PSW
	in	SIO1BD	; flush user number
	lda	DMANRsize; if len = 0, don't use DMA
	ora	A
	jrnz	..DMA
	nop
	in	SIO1BD	; get message byte
	shld	REC.HL
	lhld	DMANRadr; get buffer address
	mov	M,A	; put message into buffer
	lhld	REC.HL
	in	SIO1BD	; flush first CRC byte
	jmpr	..ret
..DMA:	mvi	A,87h	; enable DMA
	out	DMA
..ret:	pop	PSW
	ei
	reti
.page
; SDLC receive interrupt on last char
REClast:
	ei 
	sspd	REC.SP
	lxi	SP,RECstck
	push	H
	push	D
	push	B
	push	PSW
	lda	DMANRsize; check whether DMA was used
	ora	A
	jrz	..fin
	mvi	A,0C3h	; deprogram the DMA chip
	out	DMA
..fin:	in	SIO1BD	; throw away second CRC byte
	lda	RECstat
	mov 	B,A
	mvi	A,1	; get receive status
	out	SIO1BC
	in	SIO1BC
	ani	11100000b; mask out relevant bits
	set	4,A
	sta	RECstat
	mvi	A,18h
	out	SIO1BC	; reset the SIO1B chip
..ret:	pop	PSW
	pop	B
	pop	D
	pop	H
	lspd	REC.SP
	reti
;----------
; DMA transmit complete interrupt
DMATdone:
	push	PSW
	mvi	A,0C3h	; reset the DMA chip
	out	DMA
	pop	PSW
        ei
        ret 
.page
;---------------
; DMA receive complete interrupt
DMARdone:
	push	PSW
	push	D
	shld	REC.HL
	mvi	A,0C3h	; reset the DMA chip
	out	DMA
	mvi	A,21h	; now interrupt on every char
	out	SIO1BC
	mvi	A,11110100b
	out	SIO1BC
	lhld	1
	lxi	D,SIO1vect+4
	dad	D
        lxi	D,RECflush; setup the DMA vector
	mov	M,E
	inx	H
	mov	M,D	  ;store the DMA vector
	lhld	REC.HL
	pop	D
	pop	PSW
	ei
	ret
;---------------
; SDLC receive interrupt on every char
RECflush:
	push	PSW
	in	SIO1BD	; flush this char away
	pop	PSW
	ei
	reti
;---------------
; SIO commands
SENDprog:
	.byte	    00011000b ; channel reset
	.byte	  3,00100000b ; auto enables
	.byte	14h,00100000b ; SDLC mode
	.byte	11h,11000100b ; no interrupts
	.byte	  5,11101011b ; transmitter enable
	.byte	    10000000b ; reset CRC generator
SEND$	==	.-SENDprog
.page
RECprog:
	.byte	    00011000b ; channel reset
	.byte	  2,SIO1vect+3; interrupt vector
	.byte	  4,00100000b ; SDLC mode
	.byte	15h,10000000b ; transmit disable
	.byte	  3,11111100b ; receiver info
	.byte	6
RECadr:	.byte	0	      ; user number
	.byte	  7,01111110b ; flag byte
	.byte	11h,11101100b ; interrupt on first byte
	.byte	23h
RECable:.byte	    11111101b ; enable receiver
REC$	==	.-RECprog
;---------------
; DMA commands
DMANSprog:
	.byte	0C3h	; master reset		     2D
	.byte	0C7h	; reset port A		     2D
	.byte	0CBh	; reset port B		     2D
	.byte	79h	; write
DMANSadr:.word	0	; filled by SENDNET or RECstart
DMANSsiz:.word	0	; filled by SENDNET or RECstart
	.byte	14h	; port A inc, memory	     1B
	.bytå	28è	» porô Â fixed¬ I/Ï	     1B
	.byte	95h	; byte mode		     2B
	.byte	SIO1BD	; port B
	.byte	12h	; interrupt at end of block
	.byte	DMAvect+3; interrupt vector
	.byte	92h	; stop at end of block
	.byte	0CFh	; load starting address      2C
	.byte	5	; write
	.byte	0CFh	; load starting address	     1A
	.byte	0ABh	; enable interrupts	     2D
DMAN$	==	.-DMANSprog
;
DMANRprog:
	.byte	0C3h	; master reset		     2D
	.byte	0C7h	; reset port A		     2D
	.byte	0CBh	; reset port B		     2D
	.byte	7Dh	; read
DMANRadr:.word	0	; filled by SENDNET or RECstart
DMANRsiz:.word	0	; filled by SENDNET or RECstart
	.byte	14h	; port A inc, memory	     1B
	.bytå	28è	» porô Â fixed¬ I/Ï	     1B
	.byte	95h	; byte mode		     2B
	.byte	SIO1BD	; port B
	.byte	12h	; interrupt at end of block
	.byte	DMAvect+3; interrupt vector
	.byte	92h	; stop at end of block
	.byte	0CFh	; load starting address      2C
	.byte	1	; read
	.byte	0CFh	; load starting address	     1A
	.byte	0ABh	; enable interrupts	     2D
.page
.sbttl "SUBROUTINES"
;---------------
; Get CP/M disk name (A, B, C, or D) from user
;
getCPMdsk:
	call	CONIN	  ; get console chr
	cpi	3	  ; Is chr a ctrl-C?
	jz	0	  ; Yes. Abort.
	cpi	'D'+1	  ; Is it too large?
	jrnc	getCPMdsk ; Yes. Fetch next chr
	cpi	'A'       ; Is it too small?
	jrc	getCPMdsk ; Yes. Fetch next chr
	push	PSW	  ; No. Echo valid chr
	sta	savdsk
	pop	PSW
	sui	'A'       ; Make it 0,1,2, etc
	ret	 	  ; and return.
;------------------
; Subroutine: stobyt
; Regs  in: C 
; Regs out: C
; Regs destroyed: none
;			
STOBYT:
	push PSW 
	push B 
	push D 
	push H
	lhld	bufchr		; get next chr addr
	mov	M,C		; write it to buffer
	inx	H		; increment buff addr
	shld	bufchr		; save next chr addr
;increment counter and test for full buffer
	lda	bufcnt
	inr	A
	cpi	128		; 128 chrs ready?
	jrc	..notfull	; No.
	call	Diskit		; Yes. Put it on disk
				; if disk flag is set.
	jmp	BUFreset	; Reset, and return.
..notfull:
	sta	bufcnt		; save chr counter
	mov	A,C		; restore chr
	pop H 
	pop D 
	pop B 
	pop PSW
	ret
.page
;---------------
;Subroutine:	stoMAPbyt
; Regs  in:	A = disk number of MAPbyte to store
; Regs out:	none
;Destroyed:	any and/or all registers

; Save the current assignment for restoration.
stoMAPbyt:
	lda	04	; get current drive
	sta	orgdriv	; and save for restoration.
	call	CPMmap	; get current assignment
; BIOS address of the byte returns in HL
	sta	MAPbyt	; save it for later restoration
	ret		; and return.
;------------------
;		Subroutine: wrtbuf
; Regs  in:
; Regs out:
; Destroyed:
;Write a character to the error buffer
WRTBUF:
	push	H
	lhld	errbufadr
	mov	M,C
	inx	H
	mvi	M,EOF	; tag on an EOF (1Ah)
	shld	errbufadr
	pop	H
	ret
;------------------
;		Subroutine: putEOF
; Regs  in:	none
; Regs out:	none
; Destroyed:	none
;Put an End of File marker (1Ah) at end of buffer.
putEOF:
	push	H
	lhld	errbufadr
	mvi	A,EOF
	mov	M,A
	inx	H
	mov	M,A
	inx	H
	mov	M,A
	pop	H
	ret
.page
;------------------
; Subroutine: Diskit: The 128 character buffer is full
;	              so we open CONFILE.TXT and write
;		      the buffer to it.
; Regs  in:	None
; Regs out:	None
; Regs destroyed:	None
;
DISKIT:
;Make sure the disk-write flag is set
	lda 	dskflg
	cpi	0FFh	; is the flag set?
	rnz		; no, return to stobyt
;reset the bytes-per-read value
	lxi	B,128	; normal I/O byte value
	call	SETBYT
;select the error disk
	lda	ERRDSK
	call	resMAPbyt
;reset the dma
	lxi	D,80h
	mvi	C,setdma
	call	BDOS
;open the file
	mvi	C,open	; prepare to open file
	lxi 	D,FCB   ; File Control Block addr
	call 	BDOS
;Get to last record of file and 
; find FCB's record count then set FCB's current record
	lxi	H,FCB  
	lxi	D,15
	dad	D
	mov	A,M	; get rec count in acc
	lxi     H,FCB
	lxi	D,32
	dad	D	; load cur rec addr 
	mov	M,A	; next rec is now cur I/O rec
;set dma address
	lxi	D,dskbuf ; 128 chr buffer addr
	mvi	C,setdma ; prepare to set dma
	call	BDOS
;write the record
	lxi 	D,FCB   ; File Control Block addr
	mvi	C,wnr	;write next record
	call 	BDOS ; write buffer to disk
.page
;check for successful write
	cpi	0	   ; errors?
	jz  	resDMA     ; No.
	lxi	H,badwrmsg ; Yes.
	call	prtmsg
	lda	ERRDSK
	adi	'A'
	mov	C,A
	call	CONOUT
	mvi	C,':'
	call	CONOUT
	jmpr	resDMA
;---------------
;reset dma
resDMA:	lxi	D,80h
	mvi	C,setdma
	call	BDOS
;close file CONFILE.TXT
	lxi 	D,FCB   ; File Control Block addr
	mvi	C,close
	call	BDOS	  ; close the file
	cpi	0FFh	  ; OK close?
	rnz		  ; Yes. Return.
	lxi	H,badwrmsg; No. Load err msg
	call	prtmsg
	lda	ERRDSK
	adi	'A'
	mov	C,A
	call	CONOUT
	mvi	C,':'
	call	CONOUT
	ret		  ; and return.
;---------------
;  Suboutine: BUFreset
; Reset variables, buffers, counters, and disk selects.
BUFreset:
	lda	DSKNAME	   
	mvi	B,2
	call	chaMAPbyt ; select test disk
	lbcd	BUFLEN  ; restore the original bytes-
	call	SETBYT  ; per-read value
	lxi	H,dskbuf; reset buffer for the next
	shld	bufchr	; 128 characters in buffer
	mvi	A,0     
	sta	bufcnt	; reset counter
resume:	pop H 
	pop D 
	pop B 
	pop PSW
	ret
.page
SELDSK:
	lhld	WBOOT
	lxi	D,18h
	dad	D
	pchl
CONST:
	lhld	WBOOT
	lxi	D,03h
	dad	D
	pchl
CONOUT:
;The chr arrives in Reg C.
	lda	errflg	; is this part of an err msg?
	cpi	0FFh
	jrnz	chrout	; just output the chr
	call	wrtbuf	; put chr in error buffer (R)
	lda	dskflg	; do we put this into disk buf?
	cpi	0FFh
	cz	stobyt	; put it in disk buffer
chrout:	lhld	WBOOT
	lxi	D,09h
	dad	D
	pchl
CPMMAP:
	lhld	WBOOT
	lxi	D,60h
	dad	D
	pchl
SETBYT:
	lhld	WBOOT
	lxi	D,66h
	dad	D
	pchl
NACKpoll:
	lhld	1
	lxi	D,72h
	dad	D
	pchl
.page
;---------------
;Subroutine:	chaMAPbyt
; Regs  in:	A = unit number to assign to
;		B = CP/M device number to assign from
; Regs out:	none
;Destroyed:	any and/or all registers
;
; Change the assignment of the CP/M drive number
; (received in B) to that of a floppy disk on the
; unit number received in the accumulator.
chaMAPbyt:
	push	PSW	; Save unit number
	mov	C,B
	call	SELDSK	; select unit 0 f
	call	CPMmap	; get current MAPbyte byte addr
; Current unit 0 assignment (network,etc) returns in A
; BIOS address of the byte returns in HL
	pop	B	  ; Restore unit number in B
	lda	DENSbyt	  ; Get floppy density code
	ora	B	  ; A = A <or> B = New MAPbyte
	mov	M,A	  ; Store it in the BIOS
	ret

;----------
;Subroutine:  resMAPbyt
; Regs  in:	A = disk number of MAPbyte to restore.
; Regs out:	none
;Destroyed:	any and/or all registers

; Restore the error disk assignment
resMAPbyt:
	lda	orgdriv	; Get our original disk
	mov	C,A	; and put it in C
	call	SELDSK	; and select buffer-write unit.
	call	CPMmap	; get BIOSmap addr
;Current unit assignment returns in A
;BIOS address of the byte returns in HL
	lda	MAPbyt	; original assignment
	mov	M,A	; restore previous assignment
	ret		; and return.
.page
.sbttl	"SCOPE SUBROUTINES"
; The following routines are designed for flagging
; various bits on the second parallel port. This
; allows the technicians to obtain data without
; having to consult the CRT.
;
; bit 0 - set high during net receives, otherwise low.
; bit 1 - set high during net sends, otherwise low.
; bit 2 - set high after a network timeout (receive).
; bit 3 - unused	
; bit 4 - unused
; bit 5 - unused
; bit 6 - unused
; bit 7 - unused
;
; to set a bit high use the following code:
; 	mvi	A,2 (or other bit number)
;	call	upbit
;
; to set a bit low use the following code:
; 	mvi	A,2 (or other bit number
;	call	downbit
;
;----------------
; Upbit and Downbit
; Regs  in: A=bit number to be raised or lowered.
; Regs out: none	
; Destroyed: none
; Set/Reset the bit number received in A (0-7) on PP2.
;
;A= bit number to raise
upbit:	push	PSW
	push	B	  ; save users regs
	ora	A 	  ; is bit number 0 to be on?
	mov	B,A	  ; save bit number as counter
	mvi	A,1	  ; start off with 0th bit set
	jrz	..upbyte  ; jump around computation
			  ; if its only bit 0, because
			  ; the 0th bit was just set.
..loop: rlc
	djnz	..loop	  ; rotate to proper bit setting
..upbyte:
	mov	B,A	  ; bit pattern is in B
	lda	PP2byt	  ; old bit pattern in A
	ora	B	  ; turn on our bit
	jmp	SENDbyt
.page
;
;A= bit number to lower
downbit:
        push	PSW
	push	B	  ; save users regs
	ora	A 	  ; is it bit 0?
	mov	B,A	  ; save bit number as counter
	mvi	A,1	  ; start off with 0th bit set
	jrz	..downbyt ; jump around computation
			  ; if its only bit 0, because
			  ; the 0th bit is already set.
..loop: rlc
	djnz	..loop	  ; rotate to proper bit setting
..downbyt:
	cma		  ; flip bits and move
	mov	B,A	  ; bit pattern into B
	lda	PP2byt	  ; old bit pattern in A
	ana	B	  ; turn off our bit

;----------
SENDbyt:
	sta	PP2byt	  ; save the new bit pattern
	out	Pport2	  ; output the pattern
	pop	B
	pop	PSW	  ; restore users regs
	ret		  ; and return.
.page
.sbttl "CONSTANTS"
;---------------
;constants
;
bufchr:	.word	0 ; filled in at START
bufcnt:	.byte	0 ; updated by stobyt,Diskit
dskflg:	.byte	0 
dskbuf:	.blkb	128 ; chr buffer for disk outp
errbufadr: .word 00h; Current spot in err buffer.
errflg:	.byte	0   ; Write flag for error buffer.
ERRDSK:	 .byte	0   ; Holder of error disk number.
DSKNAME: .byte	00
BUFLEN:	 .word	00
orgdriv:.byte	0   ; Drive to boot to when done.
DENSbyt:.byte	00h ; Density for test
MAPbyt:	.byte	00h ; Users current MAPbyte
saveER:	.byte   '0' ; user response to 'save on disk?'
savdsk:	.byte	'A' ; disk selected by user for save
;
; File Control Block  (For CP/M file management)
;
FCB:	.byte	0
	.ascii	'CONFILE TXT'
	.byte	0,0,0,0,0,0,0,0,0,0,0,0,0
	.byte	0,0,0,0,0,0,0,0,0,0,0,0,0
; The NEC765 Error buffer results are stored here.
BIOSbuf:.byte	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
constat ==	0Bh	;CP/M 11, Get Console Status
logdsk	==      0Eh	;CP/M 14, Select Disk
open	==	0Fh	;CP/M 15, Open File
close	==	10h	;CP/M 16, Close File
kill	==	13h	;CP/M 19, Delete File
create	==	16h	;CP/M 22, Create File
wnr	==	15h  	;CP/M 21, Write Sequential
setdma	==	1Ah	;CP/M 26, Set DMA Address
BIOSrty ==      4Eh
EOF     ==      1Ah
DMA	==      38h    ;DMA chip
PIOAD	==      08h    ;PIO channel A, data
SIO1BC	==      2Bh    ;SIO-1 channel B, cntrl
SIO1BD	==	29h    ;SIO-1 channel B, data
SIO1vect==	3Dh    ;SIO-1 interrupt vectrs
DMAvect	==	55h    ;DMA interrupt vector
$halfms	==	50h    ;1/2 ms delay in SENDNET
$1sec   ==      4000h  ;1 sec delay in RECNET
BDOS    ==	5      ;BDOS entry point 
WBOOT   == 	1
ctrlc   ==      03h
CR	==	0Dh
lf   	==	0Ah
SRbuff  ==      2000h  ;master send rec buff
RECbuff ==      3000h  ;master rec buffer
.page
;
; The following constants determine the length of the 
; data transmitted for the HiNet test.
;
byt1length  ==  1    ;1 byte test of HiNet
byt16length ==  16   ;16 byte test of HiNet
byt28length ==  128  ;128 byte test of HiNet
byt24length ==  1024 ;1024 byte test of HiNet
bytlength:.word    0 ;storage for byte length 
FIXbyt:.byte	0A5h
;  
; The number of sends and receives per loop is counted
; by initlp(initialize loops).  To change the receive-
; sends per loop, simply modify the number in initlp.
;
initlp  ==   20 ;initializes all loop counters
tstloop:.word initlp ;test for loops done
mascntr:.word initlp ;master send rec counter
usrcntr:.word initlp ;user send rec counter
dotcntr:.byte      3 ;outer loop for user send
loopcntr:.word	   0 ;count the send rec loops
errcntr: .word     0 ;count the send rec errors
timcntr: .byte inittim ;timeout counter
delaymas:.byte	 140 ;delay master send for reset
inittim ==        10 ;initialize the time counter
stanbr:  .byte     1 ;station number
maxstatn:.byte     0 ;storage for max stations
maxusr  ==         9 ;max number of stations
Pport2	==        02 ;Parallel port 2 address
PP2byt:	.byte	  00h;This byte is what will be
		     ;sent out of port 2.
.page
.sbttl "CRT INFO"
; All CRT user info is located here
;
savedsk:.ascii	[cr][lf]'Save ERRORS and loop info on '
	.asciz	        'disk ? (Y or N) '
dskmsg:	.asciz	[cr][lf]'Select drive (A,B,C, or D)'
waitmsg:.asciz	[cr][lf]'Wait - Creating Buffer File'
massta: .ascii 	[cr][lf]'Are we the master station? '
	.asciz 		'(Y or N)'
mastmsg:.ascii	[cr][lf]'How many test stations? '
	.asciz	[cr][lf]'(maximum = 9)'
usermsg:.ascii 	[cr][lf]'Enter user station number'
	.asciz  [cr][lf]'(Can be 1 to 9)'
strtmsg:.asciz  [cr][lf]'Hit RETURN to start'
lopmsg: .asciz  [cr][lf]'loop '
bgn1msg:.asciz          '  1 byte  '
bgn16ms:.asciz          '  16 bytes  '
bgn28ms:.asciz          '  128 bytes  '
bgn24ms:.asciz          '  1024 bytes  '
summsg: .ascii  [cr][lf]'--------------------------'
	.ascii          '-----------------------'
	.ascii		'--------------------'
       	.ascii	[cr][lf]'The following is a summary '
	.ascii		'of errors detected and '
	.asciz		'and loops completed.'
loopmsg:.asciz  [cr][lf]'number of loops completed:  '
cntrmsg:.asciz  [cr][lf]'number of errors detected: '
undlin: .ascii  [cr][lf]'--------------------------'
	.ascii          '-----------------------'
	.asciz		'--------------------'[cr][lf]
;
;The following messages are written to the disk when
;the user chooses to store the errors there.
;
hdfile:	.ascii	[cr][lf]'               HiNet test '
	.ascii  'errors stored to the disk         '
	.ascii	'                    T: this terminal '
	.asciz	'took > 1 sec to respond       '
hdfil1: .ascii  [cr][lf]'D: This terminal returned '
	.ascii  'the test bytes differently than '
	.ascii  'they were sent        '
        .ascii  'C: This terminal had a CRC error'
        .asciz  '      '[cr][lf]'   '
.page
dlaymsg:.asciz  [cr][lf]'Please wait, user catching up.'
dskerr:	.asciz	[cr][lf]'Cannot access disk.'
errmsg:	.ascii	[cr][lf]'Incorrect Entry. '
	.asciz	        ' Please try again.'[cr][lf]
error2: .ascii	[cr][lf]'maximum number of users '
	.asciz 		'is 9.  Please try again.'
badwrmsg:.asciz [cr][lf]'Can not write buffer to drive'
nodskms:.ascii  [cr][lf]'No disk specified to store '
	.ascii		'errors on so you can not '
	.asciz		'finish this way  '[lf]
Ferrmsg:.ascii	[cr][lf]'If you pushed F in error, '
	.ascii	        'first rename your confile.'
	.ascii		'txt if you want to save the '
	.ascii		'errors and restart the '
	.ascii		'master or user.'[cr][lf]
HELPmsg:.ascii	[cr][lf]'TESTNET VER '
	.byte	version+'0','.',revision+'0'
	.ascii	[cr][lf][lf][09][09]'Valid commands:'
	.ascii  [cr][lf][09][09]'---------------'
	.ascii	[cr][lf]
	.ascii	[09]'F'[09]'Finish the program'[cr][lf]
	.ascii	[09]'S'[09]'Summary of errors'[cr][lf]
	.ascii	[09]'W'[09]'Wait state'[cr][lf]
	.ascii	[09]'^C'[09]'Abort TESTNET'[cr][lf]
	.ascii	[cr][lf]'Techs: Scope output is on '
        .ascii          'parallel port 2.  Jumper '
	.ascii	        'J9 must be installed.'[lf]
	.ascii	[cr][lf][09]'D0 is high during '
	.ascii	            'network receive times.'
	.ascii	[cr][lf][09]'D1 is high during '
	.ascii	            'send times.'
	.ascii	[cr][lf][09]'D2 is set high after '
	.ascii	            'receive time-outs.'
	.asciz	[cr][lf][lf]
RESTmsg:.ascii	[cr][lf]'Enter any character to '
	.asciz	        'resume processing.' 
crlf:	.asciz	[cr][lf]
.page
.sbttl "STACK"
	.byte   76h,76h,76h,76h,76h,76h,76h,76h,76h,76h
	.byte   76h,76h,76h,76h,76h,76h,76h,76h,76h,76h
	.byte   76h,76h,76h,76h,76h,76h,76h,76h,76h,76h
	.byte   76h,76h,76h,76h,76h,76h,76h,76h,76h,76h
	.byte   76h,76h,76h,76h,76h,76h,76h,76h,76h,76h
	.byte   76h,76h,76h,76h,76h,76h,76h,76h,76h,76h
	.byte   76h,76h,76h,76h,76h,76h,76h,76h,76h,76h
	.byte   76h,76h,76h,76h,76h,76h,76h,76h,76h,76h
	.byte   76h,76h,76h,76h,76h,76h,76h,76h,76h,76h
	.byte   76h,76h,76h,76h,76h,76h,76h,76h,76h,76h
	.byte   76h,76h,76h,76h,76h,76h,76h,76h,76h,76h
	.byte   76h,76h,76h,76h,76h,76h,76h,76h,76h,76h
stack:
	.end
