www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1996/08/30/00:05:42

Xref: news2.mv.net comp.os.msdos.djgpp:8052
From: korpela AT islay DOT ssl DOT berkeley DOT edu (Eric J. Korpela)
Newsgroups: comp.os.msdos.djgpp
Subject: Re: Using inline as to multiply two fixed point #'s
Date: 30 Aug 1996 00:34:05 GMT
Organization: Cal Berkeley-- Space Sciences Lab
Lines: 81
Message-ID: <505ctt$aa2@agate.berkeley.edu>
References: <502b8n$eh6 AT crab DOT rutgers DOT edu>
NNTP-Posting-Host: islay.ssl.berkeley.edu
To: djgpp AT delorie DOT com
DJ-Gateway: from newsgroup comp.os.msdos.djgpp

In article <502b8n$eh6 AT crab DOT rutgers DOT edu>,
Roger Cowley <cowley AT crab DOT rutgers DOT edu> wrote:
>Allright, so I need functions to multiply and divide fixed point
>numbers, but I'm having problems with djgpp and inline assembly.

Isn't everyone?  :)  (Just kidding.  I love both DJGPP and gas.)
>
>fixed is just typedef long fixed
>
>say x,y, and z are all fixed
>
>x = (fixed)(65536 * 2.3);
>y = (fixed)(65536 * 3.2);
>
>asm("
>  mov _x,%eax
>  imul _y
>  mov %eax,_z
>  ");
>
>Now, there are of course complications.  Yes I made x,y,and z global
>so the inline assembler could use them.  

The first thing to do is to stop doing that.  You don't need global variables
to use them in inline assembly.  Global variable are a pain in the butt. 
Global variables make code non-reentrant.  Used the Extended assembly format.
It's not that hard.  See http://www.rt66.com/~brennan/djgpp/djgpp_asm.html.

Here's how I would write your function.....

inline fixed mul_fixed(fixed x, fixed y) 
{
  fixed z;

  asm(
    "imul %1                  "
    "shll $16,%%edx           "  /* renormalize                      */
    "shrl $16,%0              "  
    "andl $0xffff0000,%%edx   "
    "addl %%edx,%0            "  /* result is in %0  14 clocks later */
   : "=a" (z)  /* store the output (%eax) in the variable z          */
   : "b"  (y), /* load the %ebx register with variable y             */
     "0"  (x)  /* load the %eax register with variable x             */
   : "edx"     /* %edx gets clobbered                                */
  );
  return (z);
}



>                                          But here's where I get
>tripped up: a long times a long is 64 bit...so this is a 32-bit
>expanding multiply whose result is 64-bit, right?  How do I use the
>imul instruction correctly in this case, and how do I dump my result
>into z?

You appear to be forgetting to renormalize after your multiplication.
(You also have to do it before division.)  In c what you'd want to
write is.....

  z=(fixed)((((long long)x)*y)/65536);

for division you need to write  

  z=(fixed)((((long long)x)*65536)/y);

The big question is "Why use fixed point?"  The above takes 16 clocks
(1 load, 14 execute, 1 store) + call overhead on a pentium.  If you
use floating point it would take 5 cycles (1 load, 3 execute, 1 store)
+ call overhead.  Even on a 486 it's 21-50 (fixed) versus 25 (fp).

Eric 


Eric

-- 
Eric Korpela                        |  An object at rest can never be
korpela AT ssl DOT berkeley DOT edu            |  stopped.
<a href="http://www.cs.indiana.edu/finger/mofo.ssl.berkeley.edu/korpela/w">
Click here for more info.</a>

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019