Hello everyone,
I am trying to write a 16 bit proc that converts a float to ASCII. Working from a template originally written by Richard Detmer I have found that ml doesn't like the FISTTP instruction and kicks it out with a "syntax error" message. According to Raymond F. not all assemblers implement the FISTTP instruction and maybe this is true when running under NTVDM.EXE as I am doing. At any rate, can someone suggest a work-around so I can avoid using FISTTP? Below is snippet showing where the problem occurs.
fordigit:
fisub digit
fmul ten
fld st
fisttp digit ;l generates an error message. FISTP assembles but I need the truncation, not rounding
mov bx, digit
or bx, 30h
mov byte ptr [di], bl
inc di
loop fordigit
Thanks,
Mark Allyn
hi,
here a code snipped thats truncating st(0):
fstcw WORD ptr [esp-2]
movzx eax,WORD ptr [esp-2]
or eax,0c00h
mov [esp-4],ax
fldcw [esp-4]
frndint
fldcw WORD ptr [esp-2]
BTW: FISTTP is an SSE3 instruction, so you may need to use an newer ml version. (Also you processor must support it)
Hi Qword,
Thanks very much. I did some more digging and came up with what looks like the same solution as yours, but fewer lines of code. I haven't tested the speed versus your solution and I make no claims as to whether it is faster or more elegant. It just works (as does yours)
I declare a word variable in .data named ctlwrd. Then in the code I write:
fstcw ctlwrd
or ctlwrd, 110000000000b ; i.e. C00h
fldcw ctlwrd
I'm using the ml.exe that comes with MASM32. I seem to recall that it is V. 6.9. I've got 6.15 around and I could test your theory.
Thanks for your help.
Mark
Try this:
push ax
fldpi
dd 240CDB67h ; fisttp word ptr [esp]
pop ax
Works for my suite of assemblers.
Quotefstcw ctlwrd
or ctlwrd, 110000000000b ; i.e. C00h
fldcw ctlwrd
Unless you want to continue using that rounding control (i.e. truncate) until the end of your app, you would still need some more code to revert to the previous rounding control or some other one.
Assuming your app is for personal use and your processor can accept this instruction, the easiest way is not to foul around with the rounding control but hard code the instruction as described at the end of Chap. 5:
http://www.ray.masmcode.com/tutorial/fpuchap5.htm
Quote from: raymond on June 19, 2011, 02:48:10 AM
...hard code the instruction as described at the end of Chap. 5:
http://www.ray.masmcode.com/tutorial/fpuchap5.htm
Quote...the following opcodes assume that the EAX register contains the pointer.
Encoding Description
DF 08 Store as a truncated WORD
DB 08 Store as a truncated DWORD
DD 08 Store as a truncated QWORD
Raymond,
Mark codes in 16 bit, that's why I chose fisttp word ptr [esp] above. Also, why use [eax] if you simply can pop the resulting integer from the stack?
By the way: fisttp word ptr [esp] is what NDISASM.EXE sees; but it works apparently as fisttp dword ptr [esp], see attachment with a full-fledged usage example. I adapted MichaelW's PrintDec routine (http://www.masm32.com/board/index.php?topic=163.0) to dword size in order to display the result.
push eax
fldpi
fmul OneMillion
dd 240CDB67h ; hardcoded fisttp dword ptr [esp] - ndisasm.exe sees it as word, though
call PrintDec
The attachment works with ml 6.14 and higher as well as with JWasm, but remember you need /omf with 6.15 and higher, and the 16-bit linker for this archaic stuff :wink
QuoteAlso, why use [eax] if you simply can pop the resulting integer from the stack?
I used EAX register in my suggested example because it is very versatile. You can use it as a pointer to any memory area where the stored data will be most useful in the circumstances (and that register can generally be trashed without too much concern). If the most useful memory area would be the stack, you can always do it as follows:
push eax
mov eax,esp
dw 8DBh