                                                                      COMMENT ~
BCD.ASM -- BCD Conversion Routines

  From `BLUEBOOK of ASSEMBLY ROUTINES for the IBM PC & XT'
        by Christopher L. Morgan
        Copyright (C) 1984 by The Waite Group, Inc.

        >>>>>  See BCD.DOC for complete descriptions of routines.  <<<<<
 _____________________________________________________________________________

   Contents:
   ---------
   BCDIN        --  Convert from ASCII Decimal to BCD
   BCDOUT       --  Convert from BCD to ASCII Decimal
   BCD2I16      --  Convert from BCD to 16-bit Binary
   I162BCD      --  Convert from 16-bit Binary to BCD
 _____________________________________________________________________________
                                                                              ~
EXTRN   STDIN:FAR,STDOUT:FAR
;_____________________________________________________________________________
;
DATAS   SEGMENT PUBLIC
        BCDBUFF DB      18 DUP(?)
DATAS   ENDS
;_____________________________________________________________________________
;
CODES   SEGMENT
        PUBLIC BCDIN,BCDOUT,BCD2I16,I162BCD
ASSUME CS:CODES,DS:DATAS
;______________________________ BCD ROUTINES _________________________________
;Routine to convert from ASCII decimal to internal BCD format.
;
BCDIN     PROC   FAR

          PUSH   DS                    ;Save registers
          PUSH   DI
          PUSH   DX
          PUSH   CX
          PUSH   AX
;
;Set up data segment
          MOV    DX,DATAS              ;Point to data segment
          MOV    DS,AX
;
;Clear BCD buffer
          LEA    DI,BCDBUFF            ;Point to BCD buffer
          MOV    AL,0                  ;zero byte
          MOV    CX,18                 ;buffer SIze
BCDIN1:
          MOV    [DI],AL               ;zero the byte
          INC    DI                    ;Point to next byte
          LOOP   BCDIN1
BCDIN2:
;
; get the digit
          CALL   STDIN                 ;Digit comes in AL
          SUB    AL,30H                ;Subract 30H
          JL     BCDIN4                ;Check if too low
          CMP    AL,9
          JG     BCDIN4                ;Check if too high
;
;Multiply buffer by 10 and add new digit
          LEA    DI,BCDBUFF            ;Point to BCD buffer
          MOV    CX,18                 ;buffer SIze
BCDIN3:
          PUSH   CX                    ;Save counter
          MOV    DL,AL                 ;Save previous digit
          MOV    AL,[DI]               ;Pick up byte from buffer
          MOV    CL,4                  ;for a count of 4
          SAL    AX,CL                 ;Shift byte left
          OR     AL,DL                 ;Combine with previous digit
          MOV    [DI],AL               ;Result goes back
          MOV    AL,AH                 ;Prepare for next byte
          AND    AL,0FH                ;Strip to byte
          INC    DI                    ;Point to next byte
          POP    CX                    ;Restore count
          LOOP   BCDIN3
          JMP    BCDIN2
BCDIN4:
          POP    AX                    ;Restore registers
          POP    CX
          POP    DX
          POP    DI
          POP    DS
          RET                          ;Return
BCDIN     ENDP
;------------------------------------------------------------------------------
;Routine to convert from internal BCD to ASCII decimal
;
BCDOUT    PROC   FAR
          PUSH   DS                    ;Save registers
          PUSH   SI
          PUSH   DX
          PUSH   CX
          PUSH   AX
;
;Set up data segment
          MOV    AX,DATAS              ;Point to data segment
          MOV    DS,AX
          MOV    CX,18                 ;for a count of 18
          LEA    SI,BCDBUFF            ;Point ot BCD buffer
          ADD    SI,17                 ;Point ot end of BCD buffer
          MOV    DH,0                  ;Clear flag for leading zeros
BCDOUT1:
          PUSH   CX                    ;Save loop count
          MOV    AL,[SI]               ;get BCD byte
          DEC    SI                    ;And point to next
          MOV    DL,AL                 ;Save it
;
;Upper digit
          MOV    CL,4                  ;for a count of 4
          ROL    AL,CL                 ;  rotate byte
          AND    AL,0FH                ;just the digit
          OR     DH,AL                 ;Leading zeros
          JZ     BCDOUT2               ;if so skip digit
          ADD    AL,30H                ;make ASCII
          CALL   STDOUT                ;Send it out
BCDOUT2:
          POP    CX                    ;Restore count
          CMP    CX,1                  ;Last digit ?
          JNZ    BCDOUT3               ;Skip in not
          MOV    DH,0FFH               ;  set flag if so
BCDOUT3:
          PUSH   CX                    ;Save count
          MOV    AL,DL                 ;byte back
;
;Lower digit
          AND    AL,0FH                ;just the digit
          OR     DH,AL                 ;Leading zeros ?
          JZ     BCDOUT4               ;if so skip digit
          ADD    AL,30H                ;make ASCII
          CALL   STDOUT                ;Send it out
BCDOUT4:
          POP    CX                    ;Restore loop count
          LOOP   BCDOUT1
          POP    AX                    ;Restore registers
          POP    CX
          POP    DX
          POP    SI
          POP    DS
          RET                          ;Return
BCDOUT    ENDP
;------------------------------------------------------------------------------
;Routine to convert from internal BCD to internal 16-bit binary.
;
BCD2I16   PROC   FAR
          PUSH   DS                    ;Save registers
          PUSH   SI
          PUSH   CX
          PUSH   AX
;
;Set up data segment
          MOV    AX,DATAS              ;Point of data segment
          MOV    DS,AX
;
;Set up loop
          MOV    CX,18                 ;initialize counter
          LEA    SI,BCDBUFF            ;Point to buffer
          ADD    SI,17                 ;Point to end of BCD buffer
          MOV    DX,0                  ;Set DX to zero
BCD2I161:
          PUSH   CX                    ;Save loop count
          MOV    AL,[SI]               ;get BCD byte
          DEC    SI                    ;And point to next
          MOV    BL,AL                 ;Save it
;
;Upper digit
          MOV    CL,4                  ;for a count of 4
          ROL    AL,CL                 ;  rotate byte
          AND    AL,0FH                ;just the digit
          CBW
          PUSH   AX                    ;Save digit
          MOV    AX,DX
          MOV    CX,10                 ;multiplier of 10
          MUL    CX                    ;multiply
          MOV    DX,AX                 ;Result in DX
          POP    AX                    ;Restore digit
          ADD    DX,AX                 ;Add in digit
          MOV    AL,BL                 ;byte back
;
;Lower digit
          AND    AL,0FH                ;just digit
          CBW
          PUSH   AX                    ;Save digit
          MOV    AX,DX
          MOV    CX,10                 ;miltiplier of 10
          MUL    CX                    ;multiply
          MOV    DX,AX                 ;Result in DX
          POP    AX                    ;Restore digit
          ADD    DX,AX                 ;Add in digit
          POP    CX                    ;Restore loop count
          LOOP   BCD2I161
          POP    AX                    ;Restore registers
          POP    CX
          POP    SI
          POP    DS
          RET                          ;Return
BCD2I16   ENDP
;-----------------------------------------------------------------------------
;Routine to convert from internal 16-bit binary to internal BCD.
;
I162BCD   PROC   FAR
;
;A binary number is in DX
          PUSH   DS                    ;Save registers
          PUSH   DI
          PUSH   DX
          PUSH   CX
          PUSH   AX
;
;Set up data segment
          MOV    AX,DATAS              ;Point to data segment
          MOV    DS,AX
;
;Clear BCD buffer
          LEA    DI,BCDBUFF            ;Point to buffer
          MOV    AL,0                  ;zero byte
          MOV    CX,18                 ;buffer SIze
I162BCD1:
          MOV    [DI],AL               ;Clear byte
          INC    DI                    ;next byte
          LOOP   I162BCD1
;
;Put the digits in a buffer
          LEA    DI,BCDBUFF            ;Point to buffer
I162BCD2:
          MOV    AX,DX                 ;numerator
          MOV    DX,0                  ;Clear upper hALf
          MOV    CX,10                 ;Divisor of 10
          DIV    CX                    ;Divide
          XCHG   AX,DX                 ;get quotient
          MOV    BL,AL                 ;Save digit
          MOV    AX,DX                 ;numerator
          MOV    DX,0                  ;Clear upper hALf
          MOV    CX,10                 ;Divisor of 10
          DIV    CX                    ;Divide
          XCHG   AX,DX                 ;get quotient
          MOV    CL,4                  ;for a count of 4
          ROL    AL,CL                 ;  rotate digit
          AND    AL,0F0H               ;just the digit
          OR     AL,BL                 ;Combine digits
          MOV    [DI],AL               ;Put in buffer
          INC    DI                    ;next byte
          CMP    DX,0                  ;done ?
          JNZ    I162BCD2
          POP    AX                    ;Restore registers
          POP    CX
          POP    DX
          POP    DI
          POP    DS
          RET                          ;Return
I162BCD   ENDP
;-----------------------------------------------------------------------------
CODES   ENDS
;
        END
;_____________________________________________________________________________
;>>>>> Physical EOF BCD.ASM <<<<<
