;
; Basic I/O Library Routines
; GetLine, GetNum, GetChar
; PutLine, PutStr, PutNum, PutChar
; 
KEYST	EQU 1		; addr of keyboard status reg
KEYBUF	EQU 2		; addr of keyboard buffer
DISP	EQU 04E9h	; addr of cursor in display
CR	EQU 0Dh		; carr return char
LF	EQU 0Ah		; line feed char
;
; Define strings
;
EnterSTR: db 'Enter a string: $'
EnterNUM: db 'Enter a number: $'
;
; This is Main entry point for testing subs
;
Start:
	mov AX, EnterSTR
	call PutStr
	mov AX, STRBuff
	call GetStr
	call PutLine
;
	mov AX, EnterNum
	call PutStr
	call GetNum
	cmp ax,0		; note that entering '0' ends the program
	jz Quit
	call PutNum
	mov BYTE PTR [STRBuff], '$'
	mov AX, STRBuff
	call PutLine
	jmp Start
;
Quit:
	hlt		; end of Main Routine
;
; Subroutine GetStr  - get string from keyboard
;		     - place at address passed in AX reg
;		     - string should be terminated with a '?'
GetStr:
	push ax		; save str buffer addr
	push bx		; save regs used
	mov bx, ax	; bx is pointer to str space
;
GSMore:
	call GetChar	; get a char
	cmp al, CR	; if CR
	jz GSDone	; then done
	mov [bx], al	; save char in buffer
	inc bx		; inc pointer
	jmp GSMore
;
GSDone:
	mov byte ptr [bx], '$'	; delimit string	
	pop bx		; restore regs
	pop ax		; restore str buffer addr
	ret
;
; Subroutine GetNum - get 16 bit number from keyboard, ret in AX
;		    - this routine need not yet do error checking!
;
GetNum:
	push bx		; save regs used
	push cx
	push dx
	push si
	mov si,0	; clear neg flag
	mov bx,10	; multiplier
	mov ax,0
	push ax		; push zero on stack
;
GNGet:
	call GetChar	; char in al
	cmp al, CR	; if input is <CR then finish
	jz GNChk
;
	cmp al,'-'	; is number minus?
	jnz GNPos	; no, skip
	mov si,1	; set neg flag
	jmp GNGet
;
GNPos:	
	and ax, 000Fh	; conv ascii to dec
	mov cx, ax
	pop ax		; get partial
	mul bx		; mul partial by 10
	add ax, cx	; and add latest digit
	push ax		; save partial
	jmp GNGet
;
GnChk:
	mov al, CR	; print CR
	call PutChar
	pop ax		; get result
	cmp si,0	; check for neg
	jz GNDone
	neg ax		; convert to negative
;
GnDone:
	pop si		; restore regs
	pop dx
	pop cx
	pop bx
	ret
;
; Subroutine GetChar - waits for a keypress and returns char in al
;		     - char is echoed to display
GetChar:
	push dx		; save reg used
GCWait:
	mov dx,KEYST	; addr of keybrd status
	in al,[dx]
	cmp al,0	; key pressed?
	jz GCWait	; no, wait for keypress
;
	mov dx,KEYBUF	; addr of kbrd buffer
	in al,[dx]	; get key
	mov dx, DISP	; get screen addr
	out [dx], al	; echo char
	cmp al, LF	; if input is <LF then
	jnz GCDone
;
	mov al, CR	;  print <CR
	out [dx], al
;
GCDone:
	pop dx		; restore regs
	ret
;
;	Subroutine PutLine - print a string to display with <CR/<LF
;			  - addr is in AX
;			  - string is delimited by '$'
;
PutLine:
	call PutStr	; first, print the string
	mov al, CR	; then print CR
	call PutChar
	mov al, LF	; and LF
	call PutChar
	ret
;
;	Subroutine PutStr - print a string to dosplay
;			  - addr is in AX
;			  - string is delimited by '$'
;
PutStr:
	push bx		; save regs used
	mov bx, ax	; move addr to bx for indexing
PSNext:
	mov al,[bx]	; get next char
	cmp al,'$'	; end of string
	jz PSEnd	; yes, return
;
	call PutChar	; print the char
	inc bx		; point to next char
	jmp PSNext	; and loop
;
PSEnd:
	pop bx		; restore regs
	ret
;
;	Subroutine PutChar - print a single char to display
;			   - char is passed in al reg
PutChar:
	push dx		; save regs used
	mov dx, DISP	; get display addr
	out [dx],al
	pop dx		; restore regs
	ret
;
;	Subroutine PutNum - convert a 16 bit signed integer to decimal
;			  - and print to display (Assignment 2 !)
;
PutNum:
	push	cx		; save regs used
	push	dx
	mov	cx,10		; divisor of 10
	push	cx		; mark end of number on stack
	cmp	ax,0		; is number negative?
	jg	PNCont		; no, continue
;
	neg	ax		; negate (form two's complement) number
	push	ax		; store copy of ax on stack
	mov	al,'-'		; display a negative sign
	call	PutChar
	pop	ax		; restore ax
;
PNCont:
	mov	dx,0		; clear dx (high order divisor)
	div	cx		; divide ax by 10 (ax is quot, dx is rem)
	push	dx		; push rem on stack
	cmp	ax,0		; is quotient zero?
	jnz	PNCont		; no, loop
;
PNLoop:
	pop	ax		; get a digit
	cmp	al,10		; done?
	jz	PNDone		; yes, return
;
	or	al,30h		; convert to hex
	call	PutChar		; print digit
	jmp	PNLoop		; loop to get another
;
PNDone:
	pop	dx		; restore regs
	pop	cx 
	ret
;
STRBuff:  db 
end	Start 