UMBC CMSC 211

UMBC | CSEE


PutDec I: Displaying Unsigned Numbers

The biggest problem associated with numbers that the necessity of base conversion. This starts with the problem that the value 5 is not equal to character '5'!

The material we are looking at here will be improved when the material in chapters 10 and 11 are covered. This will help you understand what the subprogram GetDec and PutDec actually do.

To display was is the internal (binary) representation, the value must first be converted to decimal and then the decimal value must be converted to the corresponding characters with the repeated division by 10. Then we have to display the characters in the proper order! On top of everything else:

there is no detectable difference internally between signed and unsigned numbers.

A number is signed if it is treated as signed, and unsigned if it is treated as unsigned. (There is no reason why the same bits could not be printed once as signed and then as unsigned!) It is your responsibility to get the correct version!

One item to point out is that we can do math on characters, and when doing conversions, this can really help when trying to convert binary to decimal and the value is in the range of zero to 9:

'n' = n + '0' Try this as:

Value 0 1 2 3 4 5 6 7 8 9
ASCII code (in decimal) 48 49 50 51 52 53 54 55 56 57
Hex 30h 31h 32h 33h 34h 35h 36h 37h 38h 39h
character '0' '1' '2' '3' '4' '5' '6' '7' '8' '9'

If I wish to convert 00000111 to '7', I know that 000001112 is 710. The ASCII code for zero is 48. The hex representation for that ASCII code is 30h. That means 48 + 7 (or 30h + 7h) is 55 (or 37h), which is the code for '7'. (Another way to write the same this is '0' + 7 is '7'. Notice is does not matter which I use, as look as I have one form from the column for the character zero. Remembr that everything is in binary, 00110000 + 00000111 is 00110111. The assembler puts everything in to binary automatically for you.) If I wish to to convert the value 128, I can look at this on paper and see that I need to get three characters, '1', '2', and '8'. How can I get that?

If I divide 128 by 10, I get 12 with a remainder of 8. Then I can divide 12 by 10 and get 1 with a remainder of 2. Finally, I divide 1 by 10 and get 0 with a remainder of 1. Once I get the quotient of zero, I am done and then I take the remainders in reverse order and convert them to characters and display each one.

That means that 1 becomes '1', using the trick from above, and now '1' is displayed. Then I get 2 and convert it to '2' and display. Now my display says '12'. The last step is to convert 8 to '8' and display it, giving '128' on the screen.

When I said "Once I get the quotient of zero, I am done", oversimplified the problem. I know that but the computer does not. We know that a byte can hold the values from 0 to 255. If I do three divides when the value is zero, I will display '000'. If it is a word, then the maximum is 65,535. That is five characters. The simplest way is to do five divisions and print out the leading zeroes. That will work for every possible value! The bad news is I might not want the leading zeroes. That means that there has to be a counter to keep track of how many characters we are generating. The author has two versions, one with leading zeroes and one without.

Remember than the div simultanehan the div simultaneous computes the quotient and remainder, so we can use the stack to save the remainders for us while we continue to do the processing.

Example as a procedure

Note: The version I am showing you here will output a 32-bit unsigned value. Just put the upper 16 bits into the DX register before you call it.
;; PUTUDEC.ASM--a procedure to display the contents of ax  as an
;;  unsigned number in decimal
;;
;;   call via:
;;
;;	EXTRN	PutUDec: NEAR
;;	mov	ax, theNumber
;;	call	PutUDec
;;
;;
;;  Program text from "Assembly Language for the IBM PC Family, 
;;   Second Edition" by William B. Jones, (c) Copyright 1997, Scott/Jones Inc.
;;
INCLUDE	PCMAC.INC
	.MODEL	SMALL
	.CODE
	PUBLIC	PutUDec
PutUDec	PROC
	push	ax ;		Save Registers
	push	bx
	push	cx
	push	dx
	mov	cx, 0 ;		Initialize digit count
	mov	bx, 10 ;	Base of displayed number
PushDigs:
	sub	dx, dx ;	Convert ax to unsigned double-word
	div	bx
	add	dl, '0' ;	Compute the ASCII digit...
	push	dx ;		...push it (can push words only)...
	inc	cx ;		...and count it
	cmp	ax, 0 ;		Don't display leading zeroes
	jne	PushDigs
;
PopDigs:	;		Loop to display the digits
	pop	dx ;	 	(in reverse of the order computed)
	_PutCh	dl
	loop	PopDigs

	pop	dx ;		Restore registers
	pop	cx
	pop	bx
	pop	ax
	ret
PutUDec	ENDP
	END
  

Test (driver) program

;; TESTPUTU.ASM -- a minimal program to test putudec
;;
;;  Program text from "Assembly Language for the IBM PC Family" by
;;   William B. Jones, (c) Copyright 1997 Scott/Jones Inc.
;;
	.MODEL	SMALL
INCLUDE	PCMAC.INC
	.STACK	100h
	.DATA
	.CODE
	EXTRN	PutUDec : NEAR
TestPutU	PROC
	mov	ax, @data ;	(Not necessary as .DATA not used)
	mov	ds, ax
	mov	ax, 1234 ;	test case;
	call	PutUDec
	_Exit	0
TestPutU	ENDP
	END	TestPutU
  

Creating the executable and run

Assuming that we have put the procedures into separate files with ".asm" as the extensions, we can use the following steps: or


UMBC | CSEE