How to display a decimal number in assembly language

Manipulating characters and strings when programming using 8086 assembly language or 8088 for that matter is easier than dealing with numbers and that's because there already exists plenty of interruptions with functions that help read strings from a standard input and display them on some standard output just like that! but when it comes to numbers especially decimal numbers, things can get .. not as obvious and simple as when we program with a high level programming language like C for instance!
In the example below we will try to show how to display a decimal number to a screen! sounds easy, huh? well, it kinda is!

.model small ; we'll be using the small model of memory because there is not much code in our program so it can fit only in 64KB! I didn't choose the tiny model which would work just fine but I don't feel well about putting the code and data in the same 64KB!
.stack ; Declaring the stack which we will be using in this program heavily!
.data ; we won't need it at all but it is here ... because ... eh ... it looks cool to me! silly me!
.code ; code segment, no need to explain water by water!
start:
mov ax, @data ; these tow lines of code are necessary to get the ds register to point to the data
mov ds, ax
;segment, after all it is called DS = Data Segment!

mov ax, 99d ; put a decimal number in ax register
add ax, 321d ; add 321 to 99 and put the sum in ax
call DecimalToString ; this procedure converts the decimal number that's in ax to a string and displays it on the screen

mov ah, 4ch ; quit the program
int 21h
DecimalToString PROC ; start of the procedure
push ax
;saving ax, bx, cx, dx to the stack
push bx
push cx
push dx
xor cx, cx ; this basically do this: cx = 00000000
mov bx, 10d
; put the decimal number 10 in bx, why? patient please we'll see in a moment why!
loop1: ; label we'll be using for a loop
xor dx, dx ; to accomplish this: dx = 00000000
div bx ; divide ax by bx and put the remainder in dx! this does basically this: 420/10 with 402 = 321 + 99.
push dx ; save the remainder in the stack
inc cx ; count the number of remainders we saved in the stack.
cmp ax, 0
; are we done yet with division? we'll divide ax by bx until ax = 0
jnz loop1 ; loop until ax = 0, this instruction helps us to do the looping thank you very much!
mov ah, 02 ; 02 here is the parametere of the interruption 21 which we will be using momentarily!
loop2: ; another label which we'll use use to create another loop
pop dx ; huh! we get the last value of dx we put in the stack which is last remainder of the devision.
add dl, 48 ; add to that 48 because 48 is the ASCII code of 0 (zero). we use dl instead of dx because ASCII code are only 8 bits long so no need to use the whole 16 bits of dx.
int 21h ; call of the interruption 21 to display the character which code ASCII is in dx! yep it is no longer a number!
dec cx ; remember when we used the cx as a counter of numbers of dx (remainders) we pushed to the stack! it's time to use that counter, don't you think?!
jnz loop2 ; the instruction that lets us jump or not to the loop2 label.
pop dx ; now it is time to get out the values of the registers we put in the stack in the begining of the procedure.
pop cx
pop bx
pop ax
ret
; the return instruction! the IP (Instruction Pointer) will be pointing to the line of code that comes after the call of the procedure .
DecimalToString ENDP ; end of the procedure
end start
;end of the code! (sigh)

No comments:

Post a Comment