68k signed division problems (DIVS instruction)

Ask anything your want about Megadrive/Genesis programming.

Moderator: BigEvilCorporation

Post Reply
RamiroR
Interested
Posts: 18
Joined: Tue Jun 02, 2009 10:45 pm

68k signed division problems (DIVS instruction)

Post by RamiroR » Fri Feb 28, 2014 6:10 pm

Hello everyone. I haven't been active here for.. a long time. I just started working on a small Sega CD program (Yes, this is the Genesis forum but the problem I'm about to talk about has to do with the main M68K processor and nothing involving SCD hardware)
So I've created a simple system for showing animated sprites I have an array-like structure with each entry containing fixed point position,velocity and acceleration values. (lowest 6 bits are the fractional part)
I have this sprite that acts like a bouncing ball. It has a constant positive vertical acceleration value so it accelerates downwards (unless A,B,C are being pressed, in which case it accelerates upwards).
So, to make this sprite bounce I set the velocity this way every time the sprite touches a lower limit and then I change its sign:
VerticalAcc=VerticalAcc *4/3

In 68K asm and assuming d3 is the vertical acceleration (again, a 16 bit value whose lower 6 bits correspond to the fractional part)

Code: Select all

divs.w #4,d3
muls.w #3,d3
neg d3
While stepping with Gens debugger I noticed that the signed division of a negative value produces an invalid result
Let's say d3 is -7 ($FFF9 in two's complement)
doing

Code: Select all

move.w #-7,d3
divs.w #2,d3
for some reason, stores into the d3 register $00017FFC (highest two bytes are the remainder and lowest two bytes are the quotient), which is funny because DIVU yields the same result.
According to the 68k reference the result should be $FFFFFFFD (remainder -1,quotient -3)
For DIVS, the sign of the remainder is always the same
as the sign of the dividend (unless the remainder is zero).
So yeah that's pretty much it? What could it be? Both Gens and Fusion produce the same result.. I couldn't test it on real hardware.

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Fri Feb 28, 2014 7:02 pm

Your problem is your dividend is a LONG, but you're loading a WORD. Sign extend that MF!!
:lol:

And don't use divide on powers of two - use the arithmetic shift instead (unless you need the remainder).

RamiroR
Interested
Posts: 18
Joined: Tue Jun 02, 2009 10:45 pm

Post by RamiroR » Fri Feb 28, 2014 7:29 pm

Chilly Willy you are AWESOME! That was it! Apparently the manual I've been reading doesn't mention that (http://courses.ece.ubc.c/259/Summary%20 ... %20Set.pdf Page 21 doesn't mention that). From now on I'll just stick to the "M68000 Family Programmer's Reference Manual"
Thank you :D

PS: I wasn't familiar with the concept of sign extension so thanks for that too :P

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Fri Feb 28, 2014 10:54 pm

No problem. It's easy to miss simple things, especially if the manual doesn't point it out. Those make the most "fun" kind of bugs because it IS so simple to miss. :D

tryphon
Very interested
Posts: 316
Joined: Sat Aug 17, 2013 9:38 pm
Location: France

Post by tryphon » Sat Mar 01, 2014 8:12 am

Chilly Willy wrote: And don't use divide on powers of two - use the arithmetic shift instead (unless you need the remainder).
If you need the remainder, you use a logical "and" :D

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Sat Mar 01, 2014 8:24 am

tryphon wrote:
Chilly Willy wrote: And don't use divide on powers of two - use the arithmetic shift instead (unless you need the remainder).
If you need the remainder, you use a logical "and" :D
Well, you also need to worry about the sign, but that's certainly still faster than the mega-slow divide on the 68000. :D

RamiroR
Interested
Posts: 18
Joined: Tue Jun 02, 2009 10:45 pm

Post by RamiroR » Wed Mar 05, 2014 6:23 pm

Chilly Willy wrote:
tryphon wrote:
Chilly Willy wrote: And don't use divide on powers of two - use the arithmetic shift instead (unless you need the remainder).
If you need the remainder, you use a logical "and" :D
Well, you also need to worry about the sign, but that's certainly still faster than the mega-slow divide on the 68000. :D
Is it really that slow? What would be the other way to do it? I'm thinking of negating the number only if it's already negative, do the shifting, and negating it back into a negative number.(EDIT: I'd written positive, oops)
Last edited by RamiroR on Wed Mar 05, 2014 6:55 pm, edited 1 time in total.

r57shell
Very interested
Posts: 478
Joined: Sun Dec 23, 2012 1:30 pm
Location: Russia
Contact:

Post by r57shell » Wed Mar 05, 2014 6:29 pm

Here is VERY GOOD LINK.
http://oldwww.nvg.ntnu.no/amiga/MC680x0 ... iming.HTML
I save it into bookmarks :)
It's all about "what is slower" and how much.
Image

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Wed Mar 05, 2014 6:52 pm

RamiroR wrote:
Chilly Willy wrote:
tryphon wrote: If you need the remainder, you use a logical "and" :D
Well, you also need to worry about the sign, but that's certainly still faster than the mega-slow divide on the 68000. :D
Is it really that slow? What would be the other way to do it? I'm thinking of negating the number only if it's already negative, do the shifting, and negating it back into a positive number.
That's probably the fastest way to handle it, and will be much faster than divide for certain.

Gigasoft
Very interested
Posts: 95
Joined: Fri Jan 01, 2010 2:24 am

Post by Gigasoft » Thu Mar 06, 2014 1:46 am

You can divide a signed number by a power of 2 in this way.

Signed division:

Code: Select all

tst.w d0
bpl positive
add.w #Divisor-1, d0
positive:
asr.w #BitCount, d0
Signed remainder:

Code: Select all

and.w #Divisor+$7fff, d0
bpl positive
subq.w #1, d0
or.w #-Divisor, d0
addq.w #1, d0
positive:

Post Reply