UMBC CMSC 211 |
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:
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:
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.
;; 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
;; 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