Reputation: 33
I have a problem with one assembly task - I need to convert simple number (with comma- floating) input to 32-bit float representation and print it as the four-digit hex number.
Thanks.
Upvotes: 0
Views: 1291
Reputation: 21086
Here's a quick example in NASM syntax.
I used the SSE XMMx registers and functions because they are more clear and modern than the x87 FPU instructions. Also you mentioned the processor was 64bit so it should be compliant/compatible.
You can mess around with the program online at ideone.com
Read the comments and try to learn something.
global _start
section .data
ten dq 10.0
one dq 1.0
zero dq 0.0
negate dq 8000000000000000h
result dd 0.0
hex db '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
length dd 0
buffer db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
section .text
_start:
;;
;; read the fp number from stdin
;;
mov ecx, buffer
mov edx, 32
call read
mov dword [length], eax
movq xmm0, qword [zero]
movq xmm1, qword [zero]
movq xmm2, qword [ten]
movq xmm4, qword [ten]
;;
;; loop through 1 character at a time
;;
mov ebx, dword [length]
test ebx, ebx
jz quit ;; there's no input
mov ecx, 0 ;; offset counter
mov edx, 0 ;; 0 for before decimal, 1 for after decimal
mov edi, 0 ;; 0 for positive, 1 for negative
mov esi, buffer
cmp byte [esi], '-'
jne process
mov edi, 1 ;; the number is negative
inc ecx
process:
movzx eax, byte [esi + ecx]
cmp al, '.' ;; does al contain a decimal point '.'
jne next_check
test edx, edx ;; more than 1 decimal error
jnz quit
mov edx, 1
jmp continue_process
next_check:
sub eax, '0' ;; ascii digit to binary
js end_process ;; not a digit since eax is negative
cmp eax, 10
jge end_process ;; not a digit since eax is >= 10
test edx, edx ;; before or after decimal
jnz mantissa_process
mulsd xmm0, xmm2 ;; result characteristic * 10
cvtsi2sd xmm3, eax
addsd xmm0, xmm3 ;; result characteristic + next digit
jmp continue_process
mantissa_process:
cvtsi2sd xmm3, eax
divsd xmm3, xmm2 ;; next digit / current mantissa power of 10
addsd xmm1, xmm3 ;; result mantissa + next fraction
mulsd xmm2, xmm4 ;; mantissa power * 10
continue_process:
inc ecx
cmp ecx, ebx
jl process
end_process:
addsd xmm0, xmm1 ;; characteristic + mantissa
test edi, edi ;; is the number supposed to be negative ?
jz store_result
movq xmm3, qword [negate]
por xmm0, xmm3 ;; toggle the sign bit
store_result:
cvtsd2ss xmm0, xmm0 ;; double (64bit) to single (32) fp
movd eax, xmm0
mov dword[result], eax
;;
;; convert result to hex
;;
to_hex:
mov edi, buffer
mov esi, hex
mov ebx, 0
mov eax, dword [result]
mov bl, al
and bl, 0fh
mov bl, byte [esi + ebx]
mov byte [edi + 7], bl
shr eax, 4
mov bl, al
and bl, 0fh
mov bl, byte [esi + ebx]
mov byte [edi + 6], bl
shr eax, 4
mov bl, al
and bl, 0fh
mov bl, byte [esi + ebx]
mov byte [edi + 5], bl
shr eax, 4
mov bl, al
and bl, 0fh
mov bl, byte [esi + ebx]
mov byte [edi + 4], bl
shr eax, 4
mov bl, al
and bl, 0fh
mov bl, byte [esi + ebx]
mov byte [edi + 3], bl
shr eax, 4
mov bl, al
and bl, 0fh
mov bl, byte [esi + ebx]
mov byte [edi + 2], bl
shr eax, 4
mov bl, al
and bl, 0fh
mov bl, byte [esi + ebx]
mov byte [edi + 1], bl
shr eax, 4
mov bl, al
and bl, 0fh
mov bl, byte [esi + ebx]
mov byte [edi + 0], bl
;;
;; print result
;;
print_dword:
mov ecx, buffer
mov edx, 8
call write
;;
;; quit
;;
quit:
call exit
exit:
mov eax, 01h ; exit()
xor ebx, ebx ; errno
int 80h
read:
mov eax, 03h ; read()
mov ebx, 00h ; stdin
int 80h
ret
write:
mov eax, 04h ; write()
mov ebx, 01h ; stdout
int 80h
ret
Upvotes: 4