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 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. Click here for more info.