; Dec_IO.asm (sometimes named Dec_IO.pkg) ; package of 3 assembler procedures for ; performing standard decimal IO with the keyboard ; and a DOS window by Alan T. Pinck ; ; getNum accepts keyboard input and assuming ; decimal characters representing a number ; in the range 0 to 9999, converts the input ; into a binary number which is returned in ; the AX register. Leading blanks and carriage ; return codes are skipped. ; getNum returns with the Carry flag off if ; it was successful and with the Carry flag on ; if it was not (if the keyboard input did not ; start with something that could be interpretted ; as a number, or if the number exceeds 4 digits) ; ; getOp accepts keyboard input and returns the first ; non-blank, non-carriage return character entered in AL ; ; showNum displays the contents of AX (assumed to be ; a number in 2's complement form) as a decimal value ;--- data which is local to this package --- ; (do not use these names in your own program!) lastchar db 00 newline db 0Dh,0Ah,"$" num dw ? ; =========================================== ; showNum displays the 2's complement number ; in AX as a decimal number showNum proc near push ax ;save working registers push bx push cx push dx push ax mov dx,offset newline ;ensure display is on a newline mov ah,09 int 21h pop ax cmp ax,0 ;test for negative jge positive;skip ahead if positive mov ah,02 ;display character code mov dl,'-' ; minus sign int 21h mov bx,ax sub ax,bx ;ax now zero sub ax,bx ;ax now positive positive: mov bx,10 ;divide by 10 to convert to decimal mov cl,0 ;count of number of digits produced div_loop: mov dx,0 ;setup to divide dx|ax by bx idiv bx ;unsigned division: ;quotient in ax, remainder in dx push dx ;save the digit (remainder) inc cl ;keep track of number of digits cmp ax,0 ;until nothing left to divide jnz div_loop; loop back show_digit: pop dx add dl,30h ;convert digit to ASCII code mov ah,02 ;display character int 21h dec cl ;loop until all digits shown jnz show_digit pop dx ;restore working registers pop cx pop bx pop ax ret showNum endp ;========================================== ; getNum returns number input (converted to ; binary) in ax ; input is assumed to be a positive, decimal ; value with a maximum of 4 digits, terminated ; with an ASCII non-digit code ; Carry flag is set (on) if an input error is ; detected (Carry flag is clear (off) if the ; input is valid getNum proc near push bx ;save working registers push cx push dx mov num,0 mov bh,'9' ;setup for valid range testing mov bl,'0' mov cl,4 ;maximum number of digits acceptable mov al,lastchar cmp al,00 ;check if we no previous char available jne gotchar ; skip input if one already here skipwhite: mov ah,01 ;input a char int 21h gotchar: mov lastchar,al ;skip over leading blanks and cmp al,20h je skipwhite cmp al,0Dh ;carriage returns jne notwhite mov ah,02 ;but force a "newline" if carriage mov dl,0Ah ; return int 21h jmp skipwhite notwhite: ; check initial to ensure number cmp bh,al ;check that it's < '9' jc bad_digit ;error if its not sub al,bl jc bad_digit ;error if its < '0' get_loop: mov ah,0 push ax mov ax,num mov dx,10 ;decimal based system imul dx ;multiply ax by dx results in dx|ax mov num,ax ;value of prior digits times 10 pop ax ;add this digit's value add num,ax mov ah,01 ;input a character int 21h mov lastchar,al ;save it incase we're finished digits cmp bh,al ;exit getting digits if not a digit jc get_exit sub al,bl jc get_exit dec cl ;if this is not more than jnz get_loop ; 4 digits add this digit to num sub cl,1 ;otherwise exit with carry set jmp bad_digit get_exit: mov ax,num ; "good" number cmp ax,ax ; clear carry bad_digit: ;-- if we get here something is wrong ;-- by careful coding we have ensured that ;-- the carry flag will be set ;-- this is the "error" return indicator pop dx ;restore working registers pop cx pop bx ret getNum endp ;========================================== ; getOp returns the next char which is not ; a blank and not a carriage return ; as an ASCII code in AL getOp proc near push dx ;save working register mov al,lastchar ;check if char pre-read cmp al,00 je getOpchar getOploop: cmp al,20h ;skip leading blanks je getOpchar cmp al,0Dh ;and carriage returns je getOpnewline jmp getOpdone getOpnewline: mov ah,02 ;but output a newline if mov dl,0Ah ; carriage return int 21h getOpchar: mov ah,01 ;get character int 21h mov lastchar,al jmp getOploop getOpdone: mov lastchar,00 ;no extra char read pop dx ;restore work register ret getOp endp