A tiny number printing routine.
There was a time when even the most advanced computer had just a few
kilobytes of memory, and every byte of code was required to do double
and triple duty. With the advent of multi-megabyte RAM boards, the
need to pinch every byte has lessened, and programmers have indeed
forgotten some of the old ways. Let ten programmers write an ASM
program that outputs numbers and you'll get ten different algorithms,
none as compact as the one shown here. It's amazing how much power
is packed into the 30 bytes of code.
The assembly language routine below prints decimal numbers. If you
enter the routine at the label dploop with 16 (10h) in CX,
it will print hex; with 8, it will print octal; with 2, binary.
Call pdig with a small number in DL and it will be printed
as a digit; call pch and you'll print a single character.
The number printing removes leading zerores, execpt for the special
case of 0. The only 'magic' here is the use of the stack to store
the remainders of successive divisions so that they can be unstacked
and printed in proper order. They are not counted. The routine just
calls itself recursively whenever there is a nonzero quotient and
unwinds the calls to print each digit in turn. Since the routine
can't escape without printing a digit, the zero case is handled
automatically.
_dpt PROC NEAR ; Entry-point for printing in decimal
mov cx,10
dploop: ; Entry-point for printing in CX-notation
xor dx,dx
div cx ; **** SEE NOTE ****
push dx
cmp ax,0
je undo
call dploop
undo:
pop dx
pdig: ; Entry-point for printing a small digit in DL
add dl,30h
cmp dl,39h
jle pch
add al,7
pch: ; Entry-point for printing a single character
mov ah,2
int 21h
ret
_dpt ENDP
Note: If you want to be able to print 32-bit numbers, the only thing
you'll have to do is replace the line marked with **** SEE NOTE ****
with the lines:
xchg ax,bx
div cx
xchg ax,bx
div cx
When you enter the procedure the bx:ax pair should contain the 32-bit number
you want to print (bx contains the heighest 16 bits).
I even use this procedure in some of my Pascal programs, since it
is a fast and easy way to print numbers in Hex, Dec, Oct or Bin
at the users wish. Here goes a program that shows the power
of the routine:
program Bases;
procedure PrintNumber; assembler;
{ AX must hold the number (word), and
CX must hold the base. }
asm
@dploop:
xor dx,dx
div cx
push dx
cmp ax,0
je @undo
call @dploop
@undo:
pop dx
@pdig:
add dl,30h
cmp dl,39h
jle @pch
add dl,7
@pch:
mov ah,2
int 21h
end;
procedure PrintNum(Number, Base: Word); assembler;
{ PrintNumber interface. }
asm
mov ax,Number
mov cx,Base
call PrintNumber
end;
begin
Write(#13#10'$FFFF hex = ');
PrintNum($FFFF,$10);
Write(#13#10'$FFFF dec = ');
PrintNum($FFFF,10);
Write(#13#10'$FFFF (9) = ');
PrintNum($FFFF,9);
Write(#13#10'$FFFF oct = ');
PrintNum($FFFF,8);
Write(#13#10'$FFFF (7) = ');
PrintNum($FFFF,7);
Write(#13#10'$FFFF (6) = ');
PrintNum($FFFF,6);
Write(#13#10'$FFFF (5) = ');
PrintNum($FFFF,5);
Write(#13#10'$FFFF (4) = ');
PrintNum($FFFF,4);
Write(#13#10'$FFFF (3) = ');
PrintNum($FFFF,3);
Write(#13#10'$FFFF bin = ');
PrintNum($FFFF,2);
Writeln;
end.
If you want, you can call the PrintNumber procedure directly in
your program, thus saving a timeconsuming procedure-call, ie:
begin
Writeln('What is 1234h in decimal?');
Write('ohh, it is: ');
asm
mov ax,1234h
mov cx,10
call PrintNumber
end;
end.
|