COMMENT |     Procedures for number input/output    GETPUT.ASM
	Objective: Use arithmetic instructions to write simple
		   8-bit integer input and output functions:
			 PutInt8 - displays a signed integer
			 GetInt8 - reads a signed integer
	   Inputs: PutInt8 - 8-bit integer in AL register
		   Getint8 - an integer from keyboard
	   Output: According to the function. In GetInt8,
		   Carry flag is used to indicate "out of range" 
		   error if the input number is not between
|                  -128 and +127 (both inclusive).
.MODEL SMALL
.CODE
INCLUDE io.mac
PUBLIC  PutInt8, GetInt8
CR    EQU   0DH

;-----------------------------------------------------------
;GetInt8 procedure reads an integer from the keyboard and
;stores its equivalent binary in AL register. If the number
;is within -128 and +127 (both inclusive), CF is cleared;
;otherwise, CF is set to indicate out-of-range error.
;No error check is done to see if the input consists of
;digits only. All registers are preserved except for AX.
;-----------------------------------------------------------
GetInt8 PROC
	push    BX           ; save registers
	push    CX
	push    DX
	sub     DX,DX        ; DX := 0
	sub     BX,BX        ; BX := 0
get_next_char:
	GetCh   DL           ; read input from keyboard
	cmp     DL,'-'       ; is it negative sign?
	je      sign         ; if so, save the sign
	cmp     DL,'+'       ; is it positive sign?
	jne     digit        ; if not, process the digit
sign:
	mov     BH,DL        ; BH keeps sign of input number
	jmp     get_next_char
digit:
	sub     AX,AX        ; AX := 0
	mov     BL,10        ; BL holds the multiplier
	sub     DL,'0'       ; convert ASCII to numeric
	mov     AL,DL
	mov     CX,2         ; maximum two more digits to read
convert_loop:
	GetCh   DL
	cmp     DL,CR        ; carraige return?
	je      convert_done ; if so, done reading the number
	sub     DL,'0'       ; else, convert ASCII to numeric
	mul     BL           ; multiply total (in AL) by 10
	add     AX,DX        ; and add the current digit
	loop    convert_loop
convert_done:
	cmp     AX,128       
	ja      out_of_range ; if AX > 128, number out of range
	jb      number_OK    ; if AX < 128, number is valid
	cmp     BH,'-'       ; AX = 128. Must be a negative;
	jne     out_of_range ; otherwise, an invalid number
number_OK:
	cmp     BH,'-'       ; number negative?
	jne     number_done  ; if not, we are done
	neg     AL           ; else, convert to 2's complement
number_done:
	clc                  ; CF := 0 (no error)
	jmp     done
out_of_range:
	stc                  ; CF := 1 (range error)
done:
	pop     DX           ; restore registers
	pop     CX
	pop     BX
	ret
GetInt8 ENDP
	
;-----------------------------------------------------------
;PutInt8 procedure displays a signed 8-bit integer that is
;in AL register. All registers are preserved.
;-----------------------------------------------------------
PutInt8 PROC
	push    BP
	mov     BP,SP
	sub     SP,3         ; local buffer space
	push    AX
	push    BX
	push    SI
	test    AL,80H       ; negative number?
	jz      positive
negative:
	PutCh   '-'          ; sign for negative numbers
	neg     AL           ; convert to magnitude
positive:
	mov     BL,10        ; divisor  = 10
	sub     SI,SI        ; SI := 0 (SI points to buffer)
repeat1:
	sub     AH,AH        ; AH := 0 (AX is the dividend)
	div     BL           
	; AX/BL leaves AL:= quotient & AH := remainder
	add     AH,'0'       ; convert remainder to ASCII
	mov     [BP+SI-3],AH ; copy into the buffer
	inc     SI
	cmp     AL,0         ; quotient = zero?
	jne     repeat1      ; if so, display the number
display_digit:               
	dec     SI
	mov     AL,[BP+SI-3] ; display digit pointed by SI
	PutCh   AL
	jnz     display_digit ; if SI<0, done displaying
display_done:
	pop     SI           ; restore registers
	pop     BX
	pop     AX
	mov     SP,BP        ; clear local variable space
	pop     BP
	ret        
PutInt8 ENDP
	END

