Author Topic: FPU question  (Read 524 times)

LordAdef

  • Member
  • ***
  • Posts: 365
FPU question
« on: January 29, 2018, 02:47:58 PM »
Hi guys,
I wrote this procedure and tried to get away with integer division, using eax and ignoring edx. No, I´ll need FPU, which I am studying/reading... but clearly still incompetent.

I need to

->divide two values,
-> save the float value,  add and iterates the var
-> round it and move into ebx
-> float iteration continues as the loop progresses

Quote
   LOCAL byteInc:DWORD   ; the interval of bytes to read. Affects img zoom
   ; LOCAL lineInc:DWORD    ; ==> USED IN THE DWORD VERSION
        ; FPU version:
   LOCAL lineInc:REAL4      ; the interval of lines to read. Affects img zoom
   LOCAL ySum:REAL4

Part of code with commented dword version, and fpu version.
Division of two values:
Quote
         ; -----------------------------------------------------
         ; Fit to dimension: TRUE or FALSE
         ; -----------------------------------------------------
         cmp tFit, TRUE
         jnz fixedInc
         
         ; ------------------------------------------ Fit in img -----------------------------------------------------------
         ; -------- fit mapY minimap ----------
         
         ; ---------------  INTEGER version ------
          ; mov eax, map.height
          ; mov esi, MM_HEIGHT
          ; cdq
          ; div esi
          ; mov lineInc, eax   
         
         ; -------------- NEW ----------------------------
         fild map.height
         fdiv MM_HEIGHT
         fstp lineInc
         ; ---------------------------------------------------

fpu iteration, rounding and moving into ebx.:
Quote
      ; ------ reached the end of the line, next line Ptr please --------------------------------
      
      ; -------- NEW ----------------------
      fld lineInc
      fadd ySum
      fstp ySum
      mov ebx, dword ptr [ySum]   
      ; --------------------------------------      
      
      ; ------ INTEGER version ----------
      ;add ebx,  lineInc      ; we need the Ptr for the next line
      ; ------------------------------------------
      mov cc, 0            ; resets line byte back to start of line      
      mov  xPos, 0         ; reset x coord
      add yPos, 1            ; inc y coord

These are the bits I need. The dword version was perfect but I need the FPU precision. But it´s not working..... Help would be mostly appreciated  :icon_redface: :icon_redface:

ps: I didn´t quote the whole procedure to save space. I´ll be glad to post it if asked to. Cheers

jj2007

  • Member
  • *****
  • Posts: 7980
  • Assembler is fun ;-)
    • MasmBasic
Re: FPU question
« Reply #1 on: January 29, 2018, 06:42:08 PM »
Attention to the sizes:
      fld lineInc  ; ok if lineInc is REAL4 or REAL8
      fadd ySum  ; ok if REAL4
      fstp ySum  ; ok if REAL4
      mov ebx, dword ptr [ySum]  ; but it isn't REAL4, apparently :(

The assembler doesn't complain if you use float instructions for integer variables. But the result won't be correct 8)

Other than that, it's difficult to say where you could be wrong without complete code.

Btw deb is perfectly able to show you the content of the FPU.

HSE

  • Member
  • ****
  • Posts: 605
  • <AMD>< 7-32>
Re: FPU question
« Reply #2 on: January 29, 2018, 10:27:00 PM »
Just replace "fstp ySum" with "fistp dSum" where dSum is dword, then "mov ebx, dword ptr[dSum]'
 (you can make only "fistp ySum" and will work, but is error prone)

Later: you need to store the new ySum:

replace "fstp ySum" with
       " fst  ySum
         fistp dSum"

LordAdef

  • Member
  • ***
  • Posts: 365
Re: FPU question
« Reply #3 on: January 30, 2018, 10:33:54 AM »
The problem was here:
        fild map.height
         fdiv sHeight
         fstp lineInc

I changed to "fld" and it works. My problem is... map.height is a dword, shouldn´t "fild" be the right choice???
         


Quote
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         ; increment the line Ptr, searching the line for the target valeu
   LOCAL xPos:DWORD      ; x in miniMap img
   LOCAL yPos:DWORD      ; y in miniMap img
   LOCAL byteInc:DWORD   ; the interval of bytes to read. Affects img zoom

   LOCAL lineInc:REAL4      ; the interval of lines to read. Affects img zoom
   LOCAL sHeight:SDWORD   
   LOCAL ySum:REAL4
   LOCAL dSum:DWORD
      
   PUSH ebx
   PUSH edi
   PUSH esi
         ; ------ 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

   ; ----------------- 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 the Minimap x view is
   yInc      EQU   8               ; Fixed value for scale y. The bigger, the smaller the Minimap y view is   
   ; ------------------------------------------------------------------

   mov cc, 0
   mov xPos, 0
   mov yPos, 0
   mov sHeight, MM_HEIGHT         ; converts the const into a sdword

         ; -----------------------------------------------------
         ; Fit to dimension: TRUE or FALSE
         ; -----------------------------------------------------
         cmp tFit, TRUE
         jnz fixedInc
         ; ------------------------------------------ Fit in img -----------------------------------------------------------
         ; -------- fit mapY minimap ----------
         fld map.height
         fdiv sHeight
         fstp lineInc
         
         ; --------- fit mapX minimap ---------
         mov eax, cWIDTH
         mov esi, MM_WIDTH
         cdq
         div esi
         mov byteInc, eax
         jmp drawMap
         
         fixedInc:
         ; ----------------------------------------------------------------------
         ; It´s fixed.
         ; So, use the values set in xInc and yInc above
         ; ----------------------------------------------------------------------
         mov byteInc,  xInc         ; The bigger, the smaller the Minimap x view is
         mov lineInc, yInc   
   
   drawMap:   
         
   fldz            ; st(0) == 0
   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
      mov eax, byteInc
      add cc, eax            ; next byte within line
      add edi, eax            ; next byte Ptr      
      add xPos, 1            ; next x coord
      
      cmp cc, cWIDTH      ;  cWIDTH is the number of bytes/line (currently 159)
      jbe fillLine            ; it´s within line
      
      ; ------ reached the end of the line, next line Ptr please --------------------------------
;       fld ySum
;       fadd lineInc
;       fst ySum            ; sum in real4
;       fistp dSum            ; sum in dword
      
      fadd lineInc
      fist dSum
      mov ebx, dword ptr [dSum]   
      
      ;; printf ("ebx: %d \n", ebx)
      mov cc, 0            ; resets line byte back to start of line      
      mov  xPos, 0         ; reset x coord
      add yPos, 1            ; inc y coord
      
      cmp ebx, map.height    ; map.height is the num of lines of map (after is changed, according to map.style)
      jb newLinePtr   
      
   done:
      POP esi
      POP edi
      POP ebx
      ret
pCreateMiniMap endp

LordAdef

  • Member
  • ***
  • Posts: 365
Re: FPU question
« Reply #4 on: January 30, 2018, 10:35:42 AM »
Just replace "fstp ySum" with "fistp dSum" where dSum is dword, then "mov ebx, dword ptr[dSum]'
 (you can make only "fistp ySum" and will work, but is error prone)

Later: you need to store the new ySum:

replace "fstp ySum" with
       " fst  ySum
         fistp dSum"


Woking version in action. Press 1, and then when you press 4 you move to the next level, and the new miniMap is redrawn (There`re 3 maps)
Thanks HSE. It works! In fact I don´t even need to save ySum, I can iterate straight in st(0)

jj2007

  • Member
  • *****
  • Posts: 7980
  • Assembler is fun ;-)
    • MasmBasic
Re: FPU question
« Reply #5 on: January 30, 2018, 04:23:56 PM »
Works fine but I can't see any effect of pressing 4 :(

LordAdef

  • Member
  • ***
  • Posts: 365
Re: FPU question
« Reply #6 on: January 30, 2018, 05:18:06 PM »
the 4, not the side pad four, right?

Just skip the current level, and take you to the start of the next level, with the miniMap being redrawn with the new map.

HSE

  • Member
  • ****
  • Posts: 605
  • <AMD>< 7-32>
Re: FPU question
« Reply #7 on: January 31, 2018, 01:59:41 AM »
Before the proc end, "fstp st" will empty FPU       :t

LordAdef

  • Member
  • ***
  • Posts: 365
Re: FPU question
« Reply #8 on: January 31, 2018, 04:28:27 AM »
Before the proc end, "fstp st" will empty FPU       :t

Sure, is it a good practice to empty FPU after using it?

concerning my question above, map.height is a dword, but the code only worked with  "fld map.height". Wouldn´t "fild" be the right one??

jj2007

  • Member
  • *****
  • Posts: 7980
  • Assembler is fun ;-)
    • MasmBasic
Re: FPU question
« Reply #9 on: January 31, 2018, 04:51:53 AM »
Sure, is it a good practice to empty FPU after using it?
Yes, otherwise you run into trouble when you need it next time, especially in a loop.


Quote
concerning my question above, map.height is a dword, but the code only worked with  "fld map.height". Wouldn´t "fild" be the right one??

Yes, probably, but check all your types. As mentioned above, unfortunately the assemblers we use do not check the type for FPU instructions. Thus, you can write fdiv someinteger (instead of fidiv), and it will erroneously treat someinteger as a REAL4.

LordAdef

  • Member
  • ***
  • Posts: 365
Re: FPU question
« Reply #10 on: January 31, 2018, 05:01:10 AM »
Quote
Yes, probably, but check all your types. As mentioned above, unfortunately the assemblers we use do not check the type for FPU instructions. Thus, you can write fdiv someinteger (instead of fidiv), and it will erroneously treat someinteger as a REAL4.

Yep, but that´s the problem... map.height is definitely a "dword", but the code will only work with fld, not with fild

here:
Code: [Select]
         ; -------- fit mapY minimap ----------
         fld map.height    <=== this should be fild right?? (map.height == dword)
         fdiv sHeight
         fstp lineInc

jj2007

  • Member
  • *****
  • Posts: 7980
  • Assembler is fun ;-)
    • MasmBasic
Re: FPU question
« Reply #11 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?

daydreamer

  • Member
  • **
  • Posts: 223
Re: FPU question
« Reply #12 on: January 31, 2018, 05:13:39 AM »
Quote
Yes, probably, but check all your types. As mentioned above, unfortunately the assemblers we use do not check the type for FPU instructions. Thus, you can write fdiv someinteger (instead of fidiv), and it will erroneously treat someinteger as a REAL4.

Yep, but that´s the problem... map.height is definitely a "dword", but the code will only work with fld, not with fild

here:
Code: [Select]
         ; -------- fit mapY minimap ----------
         fld map.height    <=== this should be fild right?? (map.height == dword)
         fdiv sHeight
         fstp lineInc
Use int3 and use debugger to singlestep your fpu code and there you can watch what real4 value endsup in your fpu, its also good singlestep any fpu code to learn how fpu regs behave
I think it 23bits number, 1bit sign and rest of bits is info if number is very big or very small, like scientific number format

Or find right print to invoke for real4 printout
« Last Edit: January 31, 2018, 07:23:55 AM by daydreamer2 »

LordAdef

  • Member
  • ***
  • Posts: 365
Re: FPU question
« Reply #13 on: January 31, 2018, 06:18:25 AM »
Hey DDreamer,

Thanks for the tip, I´ll try the debugger. Unfortunately I´m working on a laptop that doesn´t have Olly. 

HSE

  • Member
  • ****
  • Posts: 605
  • <AMD>< 7-32>
Re: FPU question
« Reply #14 on: January 31, 2018, 10:47:50 AM »
lea eax,map
fild [eax].MapStructure.height

Or
Assume eax: ptr MapStructure
fild [eax].height