News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

FPU question

Started by LordAdef, January 29, 2018, 02:47:58 PM

Previous topic - Next topic

LordAdef

thanks HSE,

I'll try that!

LordAdef

Quote from: jj2007 on January 31, 2018, 05:10:34 AM
So, when you insert
  deb 4, "fpu in", map.height, sHeight
         ; -------- fit mapY minimap ----------
         fld map.height    <=== this should be fild right?? (map.height == dword)
         fdiv sHeight
         fstp lineInc
  deb 4, "fpu out", lineInc

... does it look right? In particular since LOCAL sHeight:SDWORD?

Yep, you´re...... cheers!

But let me ask:

MM_HEIGHT EQU 200

I´m having to load MM_HEIGHT in a dword LOCAL in order to make the code world:
fild map.height
fidiv mm_Height   <--- HERE
fstp lineInc


Are constants forbidden for FPU?

Siekmanski

.const
MM_HEIGHT dd 200 ; constant

.data
lineInc dd 0

.code
fild map.height
fidiv mm_Height   <--- HERE
fistp lineInc ; assume the output is integer?
Creative coders use backward thinking techniques as a strategy.

LordAdef

Quote
Quotefild map.height
   fidiv mm_Height   <--- HERE
   fistp lineInc ; assume the output is integer?   

lineInc must be REAL4.

But would it be a problem?  I don´t see the difference between working with a dword, and working with a int const.
Obviously I´m wrong, but why?

Siekmanski

No, it's up to you, but a line number is normally a natural number.
Of course you can use a real number, then use fstp instead of fistp.   
Creative coders use backward thinking techniques as a strategy.

jj2007

Quote from: LordAdef on February 01, 2018, 04:09:11 PMAre constants forbidden for FPU?

Ask your assembler :P

Simple solution:
MM_HEIGHT EQU 200
push MM_HEIGHT
fild dword ptr [esp]  ; there it is...
pop edx

raymond

QuoteAre constants forbidden for FPU?
Questions like this are covered in the "Simply FPU" tutorial which you can find at http://www.ray.masmcode.com/tutorial/index.html. In this case, it would be in Chapter 2.

Another detail you must remember is that MASM treats "dword" and "real4" in a strictly identical manner as plainly referring to a 32-bit value (or "qword" and "real8" as a 64-bit value). Accompanying instructions are then coded accordingly.

And, one of the most common source of error made by programmers starting to use the FPU without sufficient knowledge is "A source parameter is identified as being a REAL number type or an integer type at a specified memory address but a different type resides at that address (while still being considered as acceptable data by the FPU)". The above tutorial describes what each instruction expects from the source. For example, the "fld" instruction expects a value in the floating point format, while the "fild" instruction assumes a value supplied as a signed integer format.
Whenever you assume something, you risk being wrong half the time.
http://www.ray.masmcode.com

LordAdef

Dear Raymond,

Thanks for dropping by!

Indeed, I must say I already start reading your wonderful tutorial (Hutch has previously suggested it).

True, FPU can be a bit of a hassle when you start with it. It looks easy though... fld for float, fild otherwise... easy but not..

I mentioned about constants on my post above. Yes, I understand I cannot deal with it directly, so the push esp. In my code above I used a LOCAL instead.

My question resides, as an educational point-of-view, on the architectural reason why I cannot fild a declare int const. 

raymond

QuoteMy question resides, as an educational point-of-view, on the architectural reason why I cannot fild a declare int const.

You could consider a declared constant as a macro replacing its 'lable' with the given declared constant when the code gets assembled. I haven't tested it but I would suspect that an error would be generated when trying to use a declared constant with those ALU  integer instructions which don't allow the use of constants (such as the mul and div instructions for example). As for the FPU, none of the related instructions allow for the direct use of constants. (Only seven hard-coded constants can be loaded into the top FPU register with specific instructions, as described in Chap. 4).
Whenever you assume something, you risk being wrong half the time.
http://www.ray.masmcode.com

LordAdef

Thanks for that Raymond, you were very kind.

It´s incredible to see how much I learned from all of you in this single thread. It pushed me to research and so on. I´ll keep studying Raymond´s tutorial and improve my FPU skills. I hope this serves for the next guys looking for similar help (I always think of this when I post something). You are all wonderful people.

The code is working now! Here it´s the whole procedure. Now I´ll try and do some optmization(unecessary locals and so forth).
Attached a working version.
Start the thing, and
press 1 (top numbers, not numpad)
press 4
press 1
press 4 etc.. The miniMap should redraw new maps in blue
pCreateMiniMap proc, tFit:DWORD
; --------------------------------------------------------------------------------------------------------------
; SetPixels in a pre created img, of a minuature map of the main map
; tFit == TRUE  makes the map fit into img dimension
; tFit == FALSE x /y scales are given by constants xInc and yInc
; --------------------------------------------------------------------------------------------------------------
LOCAL  cc:DWORD ; float byte counter
LOCAL  ccFloat:REAL4 ; round byte counter
LOCAL xPos:DWORD ; x in miniMap img
LOCAL yPos:DWORD ; y in miniMap img
LOCAL ySum:REAL4 ; float y value
LOCAL dSum:DWORD ; y value
LOCAL nAdd:DWORD ; incremented address for byte value within line
LOCAL byteInc:REAL4 ; increment the line Ptr, searching the line for the target valeu
LOCAL lineInc:REAL4 ; the interval of lines to read. Affects img zoom

PUSH ebx
PUSH edi
PUSH esi

and cc, 0
and ccFloat, 0
and xPos, 0
and yPos, 0
and ySum, 0
and dSum, 0
; ----------------- Constants ---------------------------------------------------------------------------------------
byteVal EQU 32 ; the target byte we want to setPixel. 32 is space (" ")
xInc EQU 8 ; Fixed value for scale x. The bigger, the smaller
yInc EQU 8 ; Fixed value for scale y. The bigger, the smaller
; --------------------------------------------------------------------------------------------------------------------------

; --------------------------------- CREATE IMG FIRST ------------------------------------------
; First, it creates a compatible bmp
; I´m cheating: made beginPaint hdc handle (from CREATE) a global
; only to deal with the miniMap here
; ------------------------------------------------------------------------------------------------------------
invoke CreateCompatibleBitmap, gHDC, MM_WIDTH, MM_HEIGHT
  mov  hMiniMapBmp, eax
invoke SelectObject, hMiniMapDC, hMiniMapBmp

; ----------------------------------------------------------------------------
; Fit Map to MiniMap dimensions: TRUE / FALSE
; ----------------------------------------------------------------------------
cmp tFit, TRUE
jnz fixedInc
; ------------------------------------------ Fit in img -----------------------------------------------------------
; -------- fit mapY minimap ----------

fild map.height
push MM_HEIGHT
fidiv dword ptr [esp] ; map height / MiniMap height
fstp lineInc

; --------- fit mapX minimap ---------
push cWIDTH
fild dword ptr [esp]
push MM_WIDTH
fidiv dword ptr [esp] ; map width / MiniMap width
fstp byteInc

;deb 4, "fpu", cWIDTH, MM_WIDTH, byteInc ;debug
jmp drawMap

fixedInc:
; --------------------------------------------------------------------------------
; It´s fixed. Use the values set in xInc and yInc above
; --------------------------------------------------------------------------------
mov byteInc,  xInc ; the bigger value, the smaller the Minimap x view is
mov lineInc, yInc
drawMap:

xor ebx, ebx
newLinePtr:
mov edi, [map.mapLinePtr+ ebx * 4] ; Get line Ptr (map.mapLinePtr is an array of Ptr)
fillLine:
cmp byte Ptr [edi], byteVal ; 32 == space, it´s what we want
jnz nextPix ; it´s not, skip SetPixel

invoke SetPixel, hMiniMapDC, xPos, yPos, 0FFFF0Bh
nextPix:
; ----------------------------------------------------------------------------------------
; Byte is NOT 32, so we don´t setpixel and just keep going
; next byte within line
; ----------------------------------------------------------------------------------------

; ---------------- inc  byte ---------------------------------------------------------
push edi ; byte address
fild dword ptr [esp]
fadd byteInc ; add float offset to address
fistp nAdd ; round new address

; ---------------- inc counter -----------------------------------------------------
fld ccFloat ; ccFloat is the float counter
fadd byteInc ; add float offset
fst ccFloat ; save it
fistp cc ; round next count

; ---------------- udpade address and xPos ------------------------------
mov edi, nAdd ; update address
add xPos, 1 ; next x coord
cmp xPos, MM_WIDTH
jb fillLine

; ----------------------------------------------------------------------------------------
;                        End of line, next line Ptr please
; ----------------------------------------------------------------------------------------
fld ySum ; float Y val
fadd lineInc ; add float Y offset
fst ySum ; save it to float
fistp dSum ; round next line value

mov ebx, dword ptr [dSum]

and ccFloat, 0
and  xPos, 0
add yPos, 1

cmp ebx, map.height ; map.height is the num of lines of map
jb newLinePtr
done:
POP esi
POP edi
POP ebx
ret
pCreateMiniMap endp

jj2007

While there are no FPU instructions for loading constants, there are the Masm32 SDK FPxx macros doing that:

include \masm32\MasmBasic\MasmBasic.inc
  Init
  fld FP4(1234567890.1234567890)
  fld FP8(1234567890.1234567890)
  fld FP10(1234567890.1234567890)
  deb 1, "On the FPU:", ST(0), ST(1), ST(2)
EndOfCode


On the FPU:
ST(0)           1234567890.123456789
ST(1)           1234567890.123456716
ST(2)           1234567936.000000000


Note the low precision of the last one, and the order: FP4 gets loaded first, and is finally in ST(2)

raymond

Once you learn how to use the FPU, you probably should shy away from using macros such as the FPxx series. For one, writing the actual code yourself is just as fast (and sometimes faster) and you know the exact output unless you also become very familiar with the purpose and output of the macro.

For example, the FPxx macro would initialize a float value as a 'local variable' on the stack within a procedure. If you want to use that same 'constant' elsewhere outside the procedure where it was initialized, you would have to use a separate macro to reinitialize it once more. You might as well initialize it once in your .data section and use it throughout your program.
Whenever you assume something, you risk being wrong half the time.
http://www.ray.masmcode.com

jj2007

Quote from: raymond on February 03, 2018, 04:37:58 AMthe FPxx macro would initialize a float value as a 'local variable' on the stack within a procedure.
Sure?

raymond

Quote from: jj2007 on February 03, 2018, 05:23:38 AM
Quote from: raymond on February 03, 2018, 04:37:58 AMthe FPxx macro would initialize a float value as a 'local variable' on the stack within a procedure.
Sure?

I may be wrong but it looks like it to me according to its description.

Quote; **********************************************************
    ; function style macros for direct insertion of data types *
    ; **********************************************************

      FP4 MACRO value
        LOCAL vname
        .data
        align 4
          vname REAL4 value
        .code
        EXITM <vname>
      ENDM
Whenever you assume something, you risk being wrong half the time.
http://www.ray.masmcode.com

jj2007

FPxx allocates its value in the .data section, so it's always a global variable. But you are right that re-using the same memory location would be desirable. That can be done with certain macro techniques, though.

Main argument for macros is that
  fld FP4(12.3)  ; you see the value
is clearer than
  fld somefloat  ; you must consult the .data section to know the value