; CONVRT.DO  08/07/2011 RHPigford
; For T200, save this as CNVRT2.CO
; using 60000,61069-1,60000
; For M100, save this as CNVRT1.CO
; using 61880,62949-1,61880
; Read a line of ascii chrs from the
; keyboard using the LINEIN routine.
; After ENTER, values will be in a 
; string starting at KBQUE terminated
; with a null (0).

;           T200       M100
INLINE:	EQU 21750; 17988
KBQUE:	EQU 61296; 63109;term w/ 0
KYREAD:	EQU 35587; 29250;like inkey$
CLS:	EQU 20301; 16945
LCD:	EQU 23045; 19268;or RST 4
POSIT:	EQU 20379; 17020
	;T200 H= col1-40 L=row 1-16
	;M100 H= 1-40,L= 1-8
CAPS: 	EQU 4116 ; 4073

	ORG 60000 ;T200
;	ORG 61880 ;M100/T102
ENTRY:	LXI H,0;set H=0,L=0 *P Globman
	DAD SP ;add the stack pointer*
	SHLD START+1;stuff it below*
START:	LXI SP,0 ;re-estab stack ptr*
	CALL CLS
	LXI H,INTRO
	CALL DISPLY
	CALL CLRANS
	CALL INLINE;get keybd chrs
	LDA KBQUE ;get first chr
	ORA A;check for 0 chr
	RZ ;means chr was 0
	CALL CAPS
	CPI 'D'
	JZ DO_DEC
	CPI 'H'
	JZ DO_HEX
	CPI 'B'
	JZ DO_BIN
	;if no match
	JMP ERROR

DO_DEC:	;test for 0 in KBQUE
	LDA KBQUE+1
	ANA A;test for a 0
	JZ START
	CALL AS2DEC
	CALL BN2DEC
	CALL BN2HEX
	CALL BN2BIN
	CALL SHOANS
	JMP START

DO_HEX:	LDA KBQUE+1
	ANA A
	JZ START
	CALL HEX2BN
	CALL BN2DEC
	CALL BN2HEX
	CALL BN2BIN
	CALL SHOANS
	JMP START

DO_BIN:	LDA KBQUE+1
	ANA A
	JZ START
	CALL ABN2BN
	CALL BN2DEC
	CALL BN2HEX
	CALL BN2BIN
	CALL SHOANS
	JMP START

AS2DEC:	LXI H,KBQUE+1;do the conversion
	ORA A ;reset flags
	LXI D,0000H
TSTNXT:	MOV A,M ;get ascii digit
	ORA A ;if Zf set, then val=0
	RZ ;done
	SUI 30H;change ascii to dig
	JC ERROR;if below 0
	CPI 10;test for >9
	JNC ERROR
	PUSH H
	MOV L,A ;put byte in L
	MVI H,0 ;zero out H
	XCHG; swap DE<->HL
	DAD H ;add what was DE to HL 2x
	JC ERROR
	MOV C,L;put resulting Low byte
		;in C
	MOV B,H
	DAD H;add HL to HL 4x
	JC ERROR
	DAD H;add HL to HL 8x
	JC ERROR
	DAD B;add to HL 8x+2x=10x
	JC ERROR
	DAD D;add last pass val
	JC ERROR
	SHLD WORD16;because sum is HL
	XCHG ;swap DE<->HL
	POP H
	INX H;point to next byte
	JMP TSTNXT

;Build an decimal ASCII string from
;the word in WORD16, and stuff it into
;the ANSDEC bytes for later display.
;Binary No to Dec ASCII, adapted
;from Leventhal Subroutines pg 158.
;Entry:
; H=high byte of output buff adr
; L=low byte of output buff adr
; D=high byte of val to convert
; E=low byte of val to convert
;Exit:
; First byte of buffer is the length
; followed by the characters
BN2DEC:	LHLD WORD16;source value
	XCHG ;put it in DE
	LXI H,TEMP;output buff adr
	SHLD PNTR
	XCHG
	MVI A,0
	STA CURLEN
;*	MOV A,H;used only for +/- ints
;*	STA NGFLAG
	ORA A ;set flags
	JP CNVERT
	SUB A
	SUB L
	MOV L,A
	SBB A
	SUB H
	MOV H,A
CNVERT:	;HL=HL div 10 (quotient)
	;DE=HL mod 10 (remainder)
	MVI E,0
	MVI B,16
	ORA A
DVLOOP:	MOV A,L
	RAL
	MOV L,A
	MOV A,H
	RAL
	MOV H,A
	MOV A,E
	RAL
	MOV E,A
	SUI 10
	CMC
	JNC DECCNT
	MOV E,A
DECCNT:	DCR B
	JNZ DVLOOP
	RAL
	ANI 1
	DAD H
	ORA L
	MOV L,A
CHINS:	MOV A,E
	ADI 30H;'0'
	CALL INSERT
	MOV A,H
	ORA L
	JNZ CNVERT
	JMP MOVDEC

INSERT:	PUSH H
	MOV C,A
	LHLD PNTR
	MOV D,H
	MOV E,L
	INX H
	SHLD PNTR
	LDA CURLEN
	ORA A
	JZ EXITMR
	MOV B,A
MVELP:	XCHG
	MOV A,M
	XCHG
	MOV M,A
	DCX H
	DCX D
	DCR B
	JNZ MVELP
EXITMR:	MOV A,C
	MOV M,A
	LDA CURLEN
	INR A
	STA CURLEN
	DCX H
	MOV M,A
	POP H
	RET

;move chrs from TEMP+1 to ANSDEC
;decrement B each time
;first byte of TEMP = length of string
MOVDEC:	LDA CURLEN;curlen always >0
	MOV B,A
	LXI D,ANSDEC+1;address 
	LXI H,TEMP+1;skip len of TEMP
MOVE:	MOV A,M ;get the ascii val from
		;source buffer
	INX H;incr TEMP addr pointer
	XCHG ;bring ANSDEC pntr to HL
	     ;TEMP adr to DE
	MOV M,A;move byte to ANSDEC
	INX H;incr ANSDEC adr
	XCHG;put TEMP adr back in HL
	    ;and ANSDEC adr back in DE
	DCR B ;check for last chr
	RZ
	JMP MOVE

;HEX2BN
; Based on Leventhal Subroutines
; page155.

;Entry: H=ASCII more sig digit
;	L=ASCII less sig digit
;Exit:	A = binary value
;	Uses AF,BC,DE,HL
HEX2BN:	;start with KBQUE, first chr
	;but first, fill 4 bytes of 
	;TEMP with '0',then a 0 as 5th
	MVI A,'0'
	MVI C,4
	LXI H,TEMP
FILTMP:	MOV M,A
	INX H
	DCR C
	JNZ FILTMP; go back for more
	INX H
	MVI A,0
	MOV M,A
	LXI H,KBQUE
	MVI A,5;do 5 chrs of KBQUE
	MOV C,A;C holds chr count
FILCAP:	MOV A,M;get chr from KBQUE
	CALL CAPS;make it caps
	MOV M,A;put it back
	DCR C
	INX H
	JNZ FILCAP;fall thru to below
	MVI C,5
	MVI B,0
	ANA A;clear flags
	LXI H,KBQUE+1
LTH1:	;assumes at least one
	;chr in KBQUE+1
	;but if not 2 long, check for 0
	MOV A,M ;look at chr
	ORA A ;test for 0 end of KBQUE
	;ok, found end of KBQUE
	JZ MOVHEX
	;chk each chr 0-9 or A-F
	CALL CHKHEX ;test for bad chrs
	;its a good chr so keep going
	DCR C ;allowable # chrs - 1
	;error if more than 4
	INX H;not 0, add to cnt, again
	INR B;increase lth of que
	MOV A,B
;test for kbque lth here
	CPI 5
	JNC ERROR;que too long
	STA CURLEN;save lth so far
	JMP LTH1 ;go do next chr

;--------------------------
;thanks to Ken Pettit and John
;Hogerhuis, this test works now.
CHKHEX:	;is it a number 0-9?
	CPI 30h ;'0'
	JC ERROR
	CPI 03AH; '9'+1 = ':'
	JNC CHK1; > than 10 so JNC
	RET
CHK1:	;see if it is a letter
	;is it A-F?
	CPI 41H ;"A"
	JC ERROR
	CPI 47H ;"F"+1
	JNC ERROR
	RET
;--------------------------

;MOVHEX
;move 1 to 4 ascii hex chrs from
;KBQUE+1 to right side of TEMP, 
;then look to TEMP in GOODHX below
;Entry: ASCII hex chrs in KBQUE+1
;CURLEN = number of chrs to move
MOVHEX:
	LXI H,TEMP+3;start 4 bytes rt
	;of TEMP starting memory locn
	XCHG ;save TEMP adr pntr in DE
	LDA CURLEN
	MOV C,A ;put lth in C
	MVI A,0
	MOV B,A; put a 0 in B
	LXI H,KBQUE;not skip the 'H'.
	;This makes the pointer 
	;come out right. Like adding
	;4-1 =3 to KBQUE pointer so
	;it is correct.
	DAD B ;adds BC to HL
	SHLD PNTR;point to KBQUE's
	;right most character 
MOVHX1:	LHLD PNTR;get the KBQUE poiner
	MOV A,M;get next right most chr
	DCX H ;point to next left chr
	SHLD PNTR;save KBQUE pointer
	XCHG ;bring TEMP pointer to HL
	MOV M,A;save in TEMP mem locn
	DCX H ;move TEMP pointer left
	XCHG ;save decr'd TEMP pointer
	DCR C;subtract 1 from CURLEN
	;chr then go on to GOODHX
	JNZ MOVHX1;fall thru to GOODHX
		  ;if 0
;---------------------------------------;known good RHP routine as of 7/18/2011
GOODHX:	MVI C,2 ;two passes thru
	LXI H,WORD16
	INX H ;move to second mem locn
	SHLD PNTR ;point to WORD16 addr
	LXI H,TEMP;point to input str
HEX2B1:	MOV D,M ;get more sig chr
	INX H ;point to next chr
	MOV E,M ;get less sig chr
	INX H
	XCHG
	MOV A,L ;get low char
	CALL A2HEX; convert to hex
	MOV B,A ;save hex value in B
	MOV A,H	;get high char
	CALL A2HEX; convert to hex
	RLC
	RLC
	RLC
	RLC
	ORA B; OR in the low hex val
	LHLD PNTR
	MOV M,A ;save result in WORD16
	DCX H
	SHLD PNTR
	DCR C
	RZ
	LXI H,TEMP+2
	XCHG
	JMP HEX2B1
A2HEX:	SUI '0'
	CPI 10
	JC A2HEX1;branch if a is dec
	SUI 7 ;else sub offset for ltrs
A2HEX1:	RET
;---------------------------------------
;BN2BIN  RHP 7/15/2011
;Start with WORD16 value, make
;ASCII BIN output found in ANSBIN
;buffer memory.
;8 ones or zeros, spc, 8 ones or zeros
BN2BIN:	LXI H,ANSBIN+1;skip over 'B'
	MVI A,16
	STA CURLEN;hold the 16 count
	SHLD PNTR
	LHLD WORD16;put word VAL in HL
	XCHG ;put WORD16 value in DE
BYTE2:	MVI B,8;for count down
	MVI C, 00000001b
BN2B1:	MOV A,C
	RRC
	MOV C,A ;test bit moved 1 bit
		;to right, resaved
	MOV A,D ;get HIGH byte
	ORA A ;clear flags
	ANA C ;test A with C
	JNZ ONE ;not 0 = 1
	JZ ZERO ; is 0, not 1

DCRB:	LDA CURLEN
	DCR A ;count=count -1
	RZ ;all 16 bits done
	STA CURLEN
	DCR B
	JZ SWITCH
	JMP BN2B1

ONE:	LHLD PNTR
	MVI A,'1'
	MOV M,A
	INX H
	SHLD PNTR
	JMP DCRB
	
ZERO:	LHLD PNTR
	MVI A,'0'
	MOV M,A
	INX H
	SHLD PNTR
	JMP DCRB

SWITCH:	MOV D,E ;put LO byte in D,
		;go again
	LHLD PNTR
	INX H
	SHLD PNTR ;leave a space in
		; output
	JMP BYTE2

;display results in all ANS buffers
SHOANS:	LXI H,ANSDEC
	CALL DISPLY
	CALL ANYKEY
	RET
;
;BN2HEX based on routine
;in Leventhal Subr pg 152
;Entry:  binary in WORD16
;Output H=Most Sig hexascii
;	L=Least hexascii
;Run through twice to do a
;complete 16 bit word
;Place ascii in ANSHEX
BN2HEX:;convrt high nibble to ascii
	LXI H,ANSHEX+1
	SHLD PNTR; use it again!
	MVI A,2 ;count
	MOV C,A ;saved in C
	LHLD WORD16;souce val
	MOV A,H ;get the val byte
;convert high nibble to ascii
BN2HE1:	MOV B,A
	ANI F0H;11110000b;get hi nibble
	RRC
	RRC
	RRC
	RRC
	CALL NASCII
	MOV H,A;place high nibble in H
 	;then convert low nibl to ascii
	MOV A,B
	ANI 0FH ;00001111b
	CALL NASCII
	MOV L,A; return low nibble to L
	JMP BN2A2
;NASCII entry a = bin data in lo nibble
;	exit a = ascii chr
NASCII:	CPI 10
	JC NAS1
	ADI 7 ;so later adding '0' will
	      ;come out A..F
NAS1:	ADI '0'
	RET
BN2A2:	XCHG ;result in DE
	LHLD PNTR
	MOV M,D
	INX H
	MOV M,E
	INX H
	SHLD PNTR
	DCR C
	RZ ;all done if count = 0
	;get next byte
	LHLD WORD16
	MOV A,L
	JMP BN2HE1
;
ABN2BN:
;ASCII binary numbers to Binary word
;7/23/2011 Works! Validates 
;entry and find KBQUE lenth.
;Then builds new word in WORD16
;from chrs in KBQUE.
	LXI H,KBQUE+1
	MVI B,0
	MVI A,0;look for terminating 0
CHKCR:	CMP M
	JZ CHKCR1;found end of KBQUE=0
;check validity
	PUSH PSW
	MOV A,M;get a chr
	CPI 030H;ascii zero
	JC ERROR;if lower than 30h
	CPI 032H
	JNC ERROR;if higher than 31
	MOV A,B
	CPI 16
	JNC ERROR
	POP PSW
	INR B
	INX H
	JMP CHKCR
CHKCR1:	MOV A,B
	STA CURLEN
	;fall thru to ABN2BG below
;--------------------------------------
;ABN2BG: 
;arrive here with up to 16 
;known good ascii 1's or 0's
;in KBQUE. CURLEN is known.
;Build new word in WORD16.

;zero out WORD16 variable
	LXI H,WORD16
	SHLD WPNTR
	MVI A,0
	MOV M,A
	INX H
	MOV M,A
	LDA CURLEN
	MOV B,A;save total curlen

;prep DE for the later DAD
	MOV E,B;the low byte
	;is the cur length
	MVI A,0
	MOV D,A;the high byte=0
	LXI H,KBQUE;note: not KBQUE+1
	DAD D;adds contents of DE to HL
	;now HL points to last
	;chr on right side of
	;KBQUE string
	SHLD PNTR
;Construct new byte right justified 
;in place at WORD16
	;B holds CURLEN from above
	;for count down
	INR B;add 1 to cur len so
	;last chr is handled below
	MVI C,00000001B;holds test bit
	;D holds pass counter
	MVI E,8;for bit test counter
ABN2B1:	;test if done all chrs in KBQUE
	DCR B;count down the chr count
	RZ;JZ TSTEND;all done
	LHLD PNTR;points to next KBQUE
	MOV A,M;get ascii chr
	;it is either a '1' or a '0'
	CPI 030H; is it a '0'?
	JZ SKIP
;otherwise fall thru because it's a '1'
	LHLD WPNTR;point to WORD16 byte
	MOV A,M;get the building byte
	ADC C;add bit to A
	MOV M,A;save it back

SKIP:	LHLD PNTR
	DCX H;point to next left chr 
	     ;in KBQUE
	SHLD PNTR
	MOV A,C
	RLC ;move the test bit
	MOV C,A
	DCR E;did we do 8 bits?
	JNZ ABN2B1
	;or fall thru to below
	LHLD WPNTR
	INX H
	SHLD WPNTR
	DCR D;pass counter
	RZ
	JMP ABN2B1 ;go again

ERROR:	CALL CLS
	LXI H,ERRMSG
	CALL DISPLY
	CALL ANYKEY
	JMP START ;go again

DISPLY:	MOV A,M
	CPI 0;look for null terminator
	RZ
	CALL LCD
	INX H
	JMP DISPLY
	RET

ANYKEY:	LHLD ANYMSG
	CALL POSIT
	LXI H,ANYMSG+2
	CALL DISPLY
ANYKY1: CALL KYREAD
	JZ ANYKY1
	LHLD ANYCLR
	CALL POSIT
	LXI H,ANYCLR+2
	CALL DISPLY
	LHLD ANSROW;reset cursor pos
	CALL POSIT
	RET

CLRANS:	LXI H,ANSDEC+1
	MVI B,7
	MVI A,' ';fill w/ spcs
CLRAN1:	MOV M,A
	INX H
	DCR B
	JNZ CLRAN1 ;CLRTMP
;	JMP CLRAN1
CLRTMP: LXI H,TEMP;clear this too
	MVI B,7
CLRTM1:	MOV M,A;fill w/ spcs
	INX H
	DCR B
	RZ
	JMP CLRTM1

;data/variables area
INTRO:	DB 'Enter D & up to 5 digs'
	DB ' D65535=max, or',13,10
	DB 'Enter H & up to 4 hex digs'
	DB ' HFFFF=max, or';40 chr CRLF
			   ;not needed
	DB 'Enter B & up to 16 "1"s or'
	DB ' "0"s, or ',13,10
	DB 'ENTER to quit.'
	DB 13,10,0

PNTR:	DS 2
WORD16:	DS 2
WPNTR:	DS 2 ;pnt to byte in WORD16
TEMP:	DB '       ';7 spcs
CURLEN:	DS 1
ANSDEC:	DB 'd'
	DB '       ';7 spcs
ANSHEX:	DB 'h'
	DB '      ';6 spcs
ANSBIN:	DB 'b'
	DB '                 ';17 spcs
	DB 0
ERRMSG:	DB 'Input error',0
ANYMSG:	DB 8,1,'Any key',0
ANYCLR:	DB 8,1,'       ',0
ANSROW:	DB 6,1
END:	END