programming-examples/assembly/The venerable IBM-370 had a numeric format called packed decimal.asm

92 lines
3.9 KiB
NASM
Raw Normal View History

2019-11-15 12:59:38 +01:00
; 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
(which would use SBB, DAS instead of ADC, DAA).
^
.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 es,di ; load es
mov di,offset result + OPLEN - 1 ; point to result area
mov cx,OPLEN ; how big are they?
call AddPackedDecimal ; add 'em up!
.EXIT 0
;****************************************************************************
; AddPackedDecimal
;
; 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
;
;****************************************************************************
AddPackedDecimal proc
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
AddEmUp: ;
adc al,ah ; add (with carry)
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 ;
AddPackedDecimal endp
END