I'm writing a tiny routine in C, and I'd like to perform some simple FPU arithmetic without invoking CRT's libraries...
Wil this code do what I need it to do, and if so, are the waits included in finit and fwait really necessary?
The code is being inlined in a place where there are no floating point operations around for a few million clocks.
I've put one below fist because I read in the masm32 FPU tutorial that I should do this after float->int conversions
due to FPU being uber-slow, but since I've never written anything for the damn thing, I have no clue o.0
// chaosF = 3.0f;
// chaosI = (DWORD) ( chaosF * CS_PLASMA_MAX_COLORS );
__asm
{
finit
fld DWORD PTR[ chaosF ]
push CS_PLASMA_MAX_COLORS
fimul [ esp ]
fist [ esp ]
fwait
pop DWORD PTR[ chaosI ]
}
QuoteCPU enters wait state until the coprocessor signals it has finished
ts operation. This instruction is used to prevent the CPU from
accessing memory that may be temporarily in use by the coprocessor.
WAIT and FWAIT are identical
So, if you don't use FWAIT there, at the same time, FPU may try to store the converted floating point number at esp position, while CPU may try to copy the value at esp to chaosI.
And about FINIT, if you don't want a FWAIT to be issued, why don't you use FNINIT? But be shure that you understand what you are doing! (http://alpha1.dyns.net/files/CPU/24547109.pdf)
Nick
Thanx mate. I guess I'll just leave everything as it is. Including FINIT... for sheer paranoia :)
Just some final smartass remarks :bdg
The key here is the word "UNDERSTAND" and not "NOT"
In the previous example, right after you store the value at esp using FPU, you get the value using CPU. FWAIT is needed. But if you insert some code between:
fist [ esp ]
pop DWORD PTR[ chaosI ]
you may lose the FWAIT thing.
Nick
The problem is that this is an isolated inline sement, I cannot insert any code inside. There isn't one.
And if I split the thing in two and call some api in between ... that's just .. ugh ... :P
AFAIK the fwait is necessary here. I think using finit in inline asm surrounded by compiler generated code could cause some problems, and it looks to me like the fist should be a fistp.
Thanx MichaelW... Forgot to cleanup again :P
I managed to get the thing working without the CRT in pure C by using
(DWORD) ( floatingPoint * integer );
instead of
(int) ( floatingPoint * integer );
I'm not fooling...
Whenever I use (int) it attaches the SetUnhandledExceptionHandler... crt_debugger_hook ... and so on...
Only GOD knows what's going on in there... :|
A few comments.
If you are going to use "finit" everytime you are going to access the FPU, you don't need to bother cleaning up the FPU when you don't use many FPU registers (although I would strongly suggest that you do in order to get into a good habit).
When you load some value to the FPU from memory (and also when you store a value from the FPU to memory), the FPU needs to know the size of that value, regardless if it is a float or an integer. If you are using a declared variable name as the source (or destination), the declared size of that variable may be used without further qualification with some assemblers/compilers. However, when you are using indirect addressing, you MUST define the size (such as fimul dword ptr[esp]).
When you declared that chaosF = 3.0f in C, you need to be sure that it was initialized as a single-precision float (32-bit) in order to refer to it as a DWORD. If it were to be initialized as a double-precision float, and then used as a single-precision, your result would be erroneous regarless of how you refer to it in the fld instruction.
Welcome to the world of the FPU and its intricacies. However, it's still SIMPLE to learn.
Raymond