I would like to know, what values should I use to change FPU rounding mode.
.data
nearest:
??
down:
??
up:
??
zero:
??
.text
.global round
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %ecx
cmpl $1, %ecx
je
fldcw nearest
cmpl $2, %ecx
je
fldcw down
cmpl $3, %ecx
je
fldcw up
cmpl $4, %ecx
je
fldcw zero
leave
ret
I found something like this:
down:
.byte 0x7f, 0x07
up:
.byte 0x7f, 0x0b
but I don't know why somebody used it. I know I should change 8 and 9 bits, like this: 00 — round to nearest 01 — round down (toward negative infinity) 10 — round up (toward positive infinity) 11 — round toward zero
The type of rounding is determined by two bits in the control word of the FPU. You can get information about the FPU here: http://www.website.masmforum.com/tutorials/fptute/fpuchap1.htm. It's a little bit tricky to change only these two bits and left the others unchanged. Take a look at my example. I tried to be as close as possible to your code:
.data
num: .double 6.5 # play with the number!
old: .word 0
nearest: .word 0x0000
down: .word 0x0400
up: .word 0x0800
zero: .word 0x0C00
result: .double 0
fmt1: .asciz "nearest: %f -> %f\n"
fmt2: .asciz "down: %f -> %f\n"
fmt3: .asciz "up: %f -> %f\n"
fmt4: .asciz "zero: %f -> %f\n"
.text
.globl main
main:
fstcw old # store old control word
movw old, %ax
andb $0b11110011, %ah # clear RC field
orw %ax, nearest
orw %ax, down
orw %ax, up
orw %ax, zero
fldcw nearest # banker's rounding
call round
mov $fmt1, %esi
call out
fldcw down # down toward -infinity
call round
mov $fmt2, %esi
call out
fldcw up # up toward +infinity
call round
mov $fmt3, %esi
call out
fldcw zero # truncating
call round
mov $fmt4, %esi
call out
fldcw old # restore old control word
xor %eax, %eax # exit(0)
ret # GCC only needs RET
round:
fldl num
frndint
fstpl result
ret
out:
push result+4
push result
push num+4
push num
push %esi
call printf # "%f" needs a double
add $20, %esp
ret