CNC | C | C++ | Assembly | Python | R | Rust | Arduino | Solidworks | Embedded Systems

The venerable IBM-370 had a numeric format called packed decimal
which was similar to packed BCD. This program shows how one might manipulate such numbers

; bcd.asm
comment ^
This is a small demonstration program to show how one might
handle the addition of IBM 370-style packed decimal numbers
(which are similar to BCD).  This particular program imposes an
arbitrary simplifying limitation by only allowing the addition
of numbers which are both the same sign, but it would be easy to
extend by either converting all negative operands to ten's
complement and adding or by implementing a subtraction routine

^
.MODEL small             ; DOS - small model
.STACK 200h              ; allocate a bit of stack

.DATA
OPLEN   equ 4                   ; the size of operands & result (bytes)
first   db  00h, 01h, 23h, 4Ch  ; 1234 in packed decimal
second  db  00h, 00h, 00h, 9Ch  ;    9 in packed decimal
result  db  OPLEN dup (?)       ; allocate space for result

.CODE
.STARTUP
mov     si,offset first + OPLEN - 1     ; point to first op
mov     bx,offset second + OPLEN - 1    ; second op
mov     di,ds                           ;
mov     di,offset result + OPLEN - 1    ; point to result area
mov     cx,OPLEN                        ; how big are they?
.EXIT 0
;****************************************************************************
;
; add two 370-style packed decimal numbers with identical signs
;
; Entry:
;       DS:SI ==> end of first operand
;       DS:BX ==> end of second operand
;       ES:DI ==> end of pre-allocated result space
;       CX = size of operands, result (in bytes)
;
; Exit:
;       if CY set, error occurred
;       otherwise, result of addition is in result space
;
; Trashed:
;       none
;
;****************************************************************************
push    ax                      ; save used regs
push    bx
push    cx
push    dx
push    di
push    si
mov     al,[si]                 ;
mov     ah,[bx]                 ;
mov     dx,ax                   ;
and     dx,00f0fh               ; use only low nybbles in DX
and     ax,0f0f0h               ; save high nybbles in AX
cmp     dl,dh                   ; are they identical?
stc                             ; (assume they're not)
jnz     Done                    ; if not, it's an error
std                             ; set dir flag (decrement ptrs)
clc                             ; clear carry flag
push    di                      ; save original DI for later
daa                             ; decimal adjust packed BCD
stosb                           ; save result
lahf                            ; save carry flag
dec     si                      ; adjust pointer for first op
dec     bx                      ; adjust pointer for second op
sahf                            ; restore flag
mov     al,[si]                 ; fetch next digits of first op
mov     ah,[bx]                 ; fetch next digits of second op
loop    AddEmUp                 ; do 'em all (CX is counter)
pop     di                      ; restore original DI
jc      Done                    ; if carry, it's an overflow
or      [di],dl                 ; place sign nybble (and clear CY)
Done:                                   ;
pop     si                      ; restore used registers
pop     di
pop     dx
pop     cx
pop     bx
pop     ax
ret                             ;