Hi i have received email asking to explain how this code snippet works taken from my OS code example, again i taked it from Linus i belive, so credit goes to him I know that is not Win32ASM but i beliv it can be very easy adapted to work in win (just remove the BIOS call and place the char in a buffer, then TextOut the buffer after conversion) Also EDX can be used for a 32bit print
``````
;=======================================================
; print 16 bit value from DX in hexa format on Screen
; DX register has the value to print
; ======================================================
Print_Hex16:
mov   cx, 4		; 4 hex digits

PrintDigit:
rol   dx, 4		; rotate so that lowest 4 bits are used
mov   ax, 0E0Fh		; ah = request, al = mask for nybble
and   al, dl

add   al, 90h		; convert al to ascii hex (four instructions)
daa			; somebody  spent 1 hour
adc   al, 40h		; to understand how this code works..
daa			; WOW!

int   10h      ; call BIOS to print char
loop  PrintDigit
ret
;===========================================================
``````
I will skip over the BIOS output char function and the obviouse 4 digit loop to concentrate on the HARD part. ie the conversion. Now first you have to understand what are the needed output values: a hex ascii char - digits 0..9 (ASCII 30h...39h) - letters A,B,C,D,E,F (ASCII 41h...46h) the input value is trimed to the hex range:0..Fh Case 1. input is < 10decimal
``````
ADD AL,90H ;will generate a value in range 90h...99h,
DAA        ;will do nothing because is no adjust required
ADC AL,40H ;will make it in range 0d0h...0d9h, CY=0
DAA        ; adjust to 30h...39h because D is 3 over A=10=0
``````
Case 2. input is >10 decimal
``````
ADD AL,90H ;WILL GO TO 9Ah...9Fh
DAA        ;will make it 00h...05h with Carry set
ADC AL,40h ;will make it 41h...46h because of carry flag (+1)
DAA        ; will make no adjust this time
``````
WOW you see how fast and with NO Jumps/IF's we made our HEX value now? ;) Hope now everybody understands this code snippet.. It sure must be placed somewhere safe :D Code Gems or something This message was edited by BogdanOntanu, on 6/19/2001 8:08:09 PM
Posted on 2001-06-19 20:01:00 by BogdanOntanu
It's a gem, indeed, but it comes from Intel documentation originally, I believe. You want a hard one, BO? Try doing the reverse: al contains an ascii character "0"-"9" or "A"-"F", and we want to convert it to a "nibble" 0-0Fh by using bcd instructions such as daa, but no conditional jumps.
Posted on 2001-06-19 20:34:00 by Larry Hammick
I coded this two days ago. I'm just starting out with win32 asm (not asm itself). I thought that MessageBox returned the ID on the stack, but by accident (after coding the below), I forgot to pop eax off of the stack.
``````
;eax contains the 32bit value to be converted
mov   ecx, 0x10
mov   esi, Debug.message + 9
.ascii:
xor   edx, edx
div   ecx
cmp   dl, 0x3A
jl    .sto
.sto:
mov   , dl
dec   esi
cmp   eax, 0xF
jg    .ascii

cmp   dl, 0x3A
jl    .stoL
.stoL:
mov   , al
call  Prompt.debug

;***------------
Prompt:
.debug:
push  MB_OK + MB_ICONHAND
push  Debug.caption
push  Debug.message
push  0
call
pop   eax
ret

Debug:
.caption db 'Debug Message', 0
.message db '0xXXXXXXXz', 0
``````
Posted on 2001-06-19 22:17:00 by eet_1024
But how to avoid conditional jumps, eet_1024? I don't know any way, and there may not be any way.
Posted on 2001-06-19 22:32:00 by Larry Hammick
Assembled with fasm, this will pop up a message box with the value stored in edx. I'll create a version to do the reverse.
``````
format PE GUI
entry Start

include 'Win32.inc'

;***---------------------------------------------------------------***
Start:
mov   edx, 0x3A8D9B0F
;***------------------------------------------------------***
;***edx to hex string
;***
PopUp_Hex32:
mov   ecx, 0x08                  ;8 Hex digits
mov   esi, Debug.message + 2
.ascii:
rol   edx, 4                     ;Get the first digit
mov   al, 0x0F                   ;  ^^^^
and   al, dl                     ;  ^^^^
daa                              ; 4 Instruction
daa                              ; ^^^^^
mov   , al                  ;Store into message text
inc   esi                        ;Set to next offset
loop  .ascii

push  MB_OK + MB_ICONHAND
push  Debug.caption
push  Debug.message
push  0
call
push  0
call

;***---------------------------------------------------------------***

Debug:
.caption db 'Debug Message', 0
.message db '0xXXXXXXXX', 0

;***---------------------------------------------------------------***
section '.idata' import data readable writeable

dd 0,0,0,rva kernel_name,rva kernel_table
dd 0,0,0,rva user_name,rva user_table
dd 0,0,0,0,0

kernel_table:
ExitProcess dd rva _ExitProcess
dd 0
user_table:
MessageBox dd rva _MessageBoxA
dd 0

kernel_name db 'KERNEL32.DLL',0
user_name db 'USER32.DLL',0

_ExitProcess dw 0
db 'ExitProcess',0
_MessageBoxA dw 0
db 'MessageBoxA',0
``````
This message was edited by eet_1024, on 6/19/2001 10:52:49 PM
Posted on 2001-06-19 22:48:00 by eet_1024
Here is ASCII to bin with no conditional jmp's (though loop could be considered one) using only 5 (3) instructions:
``````
;******************Asc_Hex.COM***********************
;***ASCII Hex to Bin (covers upper and lower case)***
;***Assebled with FAsm*******************************
use16
org 0x100

mov   si, String
mov   cx, 22      ;22 Digits in string
Convert:
lodsb
mov   ah, al
rol   ah, 2       ;convert 0x40 to 0x01 for aad
sub   al, ah      ;Correct for 'A' != 0x40 (0x41 ¬≡ 0 mod 0xA)
loop  Convert
ret

String db '0123456789ABCDEFabcdef'
``````
Posted on 2001-06-20 02:10:00 by eet_1024
``````
thanks go to bitRAKE for showing me what DAA can do and thanks
Bogdan for giving me that little OS source.

here's my explaination (might be abit clearer for those who st-
ill don't understand what DAA actually does with the Print_hex16
.)
----------------------------------------------------------------

+-----------------------------------------+
| The great (D)isaster (A)fter (A)ddition |
+-----------------------------------------+

DAA adjust what's in AL. To fully understand it, i've played around with the debugger
with different number.

First, you have to keep in  mind that BCD doesn't deal with A..F alpha. If it sees it
will automatically convert it to decimal.And based on what i just said, A=0, B=1, C=2
D=3, E=4 and F=5 (ignore the first digit, which is always 1. eg: 10, 11, 12 ect...).

DAA also deals with overflow. So, if you have 90h as your number, DAA will not do any
thing, cause that looks like decimal already.

for example:

40h <--- daa will not change and thus, remains the same.
41h <--- daa doesn't change
42h <--- daa doesn't change
43h <--- daa doesn't change
44h <--- daa doesn't change
45h <--- daa doesn't change
46h <--- daa doesn't change
47h <--- daa doesn't change
48h <--- daa doesn't change
49h <--- daa doesn't change
---------------------------
4Ah <--- daa will adjust it, because there's "A" in there! remember, BCD has no A or
F.

how it work is that it increment 4 and A becomes 0. (my way of thinkng might
not be right, but here it goes, maybe it will help you to understand what it
actually does:

A = 10 (in decimal). It take the first digit (1) and add it to 4 and thus, 4
becomes 5. And then DAA takes the second digit as its -
target (0). and now, we have 50h after DAA.)

00 <--- daa doesn't change
01 <--- daa doesn't change
02 <--- daa doesn't change
.....
09 <--- daa doesn't change

0A <--- you know what it does... first digit (0) becomes 1 (A becomes 0). Now, think -
very careful here. What is A(hex) in dec? 10! and that's exactly what DAA doe-
s. It make it look like decimal. But if the first digit(0) was 2 or 3. It wou-
ld increment it, and thus, becomes 3 and 4 respectively. BUT!! ONLY IF the SE-
COND DIGIT is GREATER THAN 9!!!.

now, our final test (note, every above example we've gone soo far has 0 in the CF).

90 <--- daa doesn't change
.....
99 <--- daa doesn't change

9A <--- daa changes. what will 9 becomes this time? (it will not become 10,, it will -
becomes 0 (with CarryFlag SET) and A becomes 0.

9B <--- daa changes. 9 becomes 0 with CF set. B becomes 1.

and so on it goes...

----------------------------------------------------------------
``````
This message was edited by disease_2000, on 6/20/2001 1:12:40 PM This message was edited by disease_2000, on 6/20/2001 11:19:17 PM
Posted on 2001-06-20 13:12:00 by disease_2000
DAA works by adding 6 (ie A+6=10) to AL if the AF is set. Auxillary carry occurs from the lower nibble of al to the upper nibble.
Posted on 2001-06-20 17:36:00 by eet_1024
Let's see your code, disease. _eet's is the best I have seen so far, but I was hoping for something more like the bin-to-ascii manoeuvre, working on al alone, without splitting it into bitfields or using rol or similar.
Posted on 2001-06-20 23:01:00 by Larry Hammick
``````
sorry, it's my fault. I misread eet_ post again...``````
:eek:
``````i thought his code actually convert it to bin (ones and -
zeros...)
how embarrassing...
``````
Posted on 2001-06-20 23:18:00 by disease_2000
The second listing I posted implemented the Print_Hex16 as a 32 function (it also pop ups a message box with the result). The third listing converts an ASCII Hex digit in al to a bin in al. It also contains additional code to a string of ASCII Hex. Last I checked, 11pm my time (Pacific), I thought my code converted to bin (if you were refering to the third example).
Posted on 2001-06-21 00:19:00 by eet_1024
Here is another way, rather similar, one byte smaller (or two in 32-bit mode), and maybe an iota faster because no rol: .data cases db "0123456789ABCDEFabcdef" cases_ equ \$-cases .code ... mov esi,offset cases mov ecx,cases_ loopit: lodsb call myxlat loop loopit ... myxlat: sub al,40h cbw and ah,7 add al,ah ;i.e. add 7 if the input was "0"-"9" sub al,7 and al,0Fh ret I suspect that with aad somewhere, it could be improved further.
Posted on 2001-06-21 06:37:00 by Larry Hammick
I never would of thought of using cbw. I added into my code. The call instruction in your function eats up excessive time.
``````
mov esi, Cases      ;FAsm works with addresses
mov ecx, Cases.Len  ;And provides some structure

Convert:
lodsb
sub   al, 0x40
cbw
not   ah