9.2 Code Examples of binasc and ascbin

Example 9-3. binasc code example

; binasc
; By M. C. Loui, 31 Dec 1991
; Converted to NASM by Peter Johnson, Nov 2000

        GLOBAL binasc

SEGMENT code

; Subroutine binasc
; Converts from binary to ASCII string ending in '$'
; Inputs:  AX = 16-bit signed integer to be converted
;          BX = Starting offset for a 7-byte buffer to hold the result
; Outputs: BX = Offset of first nonblank character of the string
;               (may be a minus sign)
;          CL = Number of nonblank characters generated

saveax  dw      0                       ; To save original input number AX
ten     dw      10

binasc:
        push    si                      ; Save registers
        push    dx
        mov     [cs:saveax], ax

        mov     cl, 0                   ; Initialize count to 0
        mov     si, 5                   ; For SI from 5 downto 0 do

.lp0:
        mov     byte [bx+si], ' '       ;   Initialize output string
        dec     si
        jge     .lp0                    ; End for
        mov     byte [bx+6], '$'        ; End of string

        add     bx, 5                   ; Set BX to point to last char
        cmp     ax, 0                   ; If AX < 0 then
        jge     .lp1
        neg     ax                      ;   Replace by absolute value

.lp1:
        mov     dx, 0                   ; Prepare for double word division
        div     word [cs:ten]           ; Divide by 10
        add     dl, 30h                 ; Convert remainder to ASCII
        mov     [bx], dl
        inc     cl                      ; Another digit

        cmp     ax, 0                   ; AX has quotient
        je      .check
        dec     bx
        jmp     .lp1

        ; Check for negative number
.check:
        cmp     word [cs:saveax], 0
        jge     .done
        dec     bx                      ; If negative, then add minus sign
        mov     byte [bx], '-'
        add     cl, 1

.done:
        pop     dx                      ; Restore registers
        pop     si
        mov     ax, [cs:saveax]
        ret

Example 9-4. ascbin code example

; ascbin
; By M. C. Loui, 31 Dec 1991
; Converted to NASM by Peter Johnson, Nov 2000

        GLOBAL ascbin

SEGMENT code

; Subroutine ascbin
; Converts from ASCII string to binary
; Inputs:  BX = Starting offset of first char of ASCII string
; Outputs: AX = Signed 16-bit number having value of ASCII string
;          BX = Offset of first non-convertible character
;          DL = Status of this call
;               0 if no conversion errors
;               1 if string had no valid digits
;               2 if string had too many digits
;               3 if overflow
;               4 if underflow (too negative)
;
; Revised: 12/17/92 by Tom Maciukenas (ECE291 TA)

ten     dw      10
minus   db      0                       ; 1 if input is negative
digits  db      0                       ; Counts number of digits
status  db      0

ascbin:
        push    si                      ; Save registers
        push    dx

        ; Initialize
        mov     ax, 0
        mov     byte [cs:minus], 0      ; Assume nonnegative
        mov     byte [cs:digits], 0

        ; Skip leading spaces
.spaces:
        cmp byte [bx], ' '
        jne     .signs
        inc     bx
        jmp     .spaces

        ; Check for leading '+' or '-'
.signs:
        cmp     byte [bx], '+'          ; If '+', skip it
        je      .incbx
        cmp     byte [bx], '-'          ; If '-', set minus flag
        jne     .scan                   ;   else scan the number
        mov     byte [cs:minus], 1      ; Remember minus sign

.incbx:
        inc     bx

        ; Scan string
.scan:
        mov     dl, [bx]                ; Check for valid digit
        cmp     dl, '0'
        jb      .end1
        cmp     dl, '9'
        ja      .end1
        jmp     .case                   ; Valid digit -- process it

.end1:
        cmp     byte [cs:digits], 0     ; Check for no digits
        jz      .error1
        jmp     .endok

.case:
        inc     byte [cs:digits]        ; Keep track of number of digits
        cmp     byte [cs:digits], 5     ; Check for too many digits
        jg      .error2
        mov     dh, 0                   ; Convert ASCII digit to number
        sub     dx, '0'
        mov     si, dx
        imul    word [cs:ten]           ; Multiply AX by 10
        jo      .error34
        add     ax, si                  ; At this point SI = 0, ..., or 9
        jo      .error34
        inc     bx                      ; Go to next digit
        jmp     .scan

.endok:
        mov     byte [cs:status], 0     ; Normal end
        cmp     byte [cs:minus], 1      ; Negate if necessary
        jne     .done
        neg     ax
        jmp     .done

.error1:
        mov     byte [cs:status], 1
        jmp     .done

.error2:
        mov     byte [cs:status], 2
        jmp     .done

.error34:
        cmp     byte [cs:minus], 1      ; Overflow or underflow?
        je      .ck216
        mov     byte [cs:status], 3
        jmp     .done

        ; Check for -2^16 before declaring underflow (error type 4)
.ck216:
        cmp     ax, 8000h               ; -2^16
        jne     .error4
        cmp     byte [bx+1], '0'        ; Check that next char
        jb      .ok216                  ;  is not a digit
        cmp     byte [bx+1], '9'
        ja      .ok216
        jmp     .error4

.ok216:
        mov     byte [cs:status], 0
        jmp     .done

.error4:
        mov     byte [cs:status], 4

.done:
        pop     dx                      ; Restore registers
        pop     si
        mov     dl, [cs:status]
        ret