It is currently Sun Nov 17, 2019 6:17 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 41 posts ]  Go to page Previous  1, 2, 3
Author Message
PostPosted: Sat Dec 08, 2018 9:09 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 11434
Location: Rio de Janeiro - Brazil
Yeah, an arithmetic right shift will shift the most significant bit right, but also preserve it as the most significant bit.

When used for division, an arithmetic right shift will round the result down, towards negative infinity, not towards zero.

If you try to divide -3 by 2, the correct result is -1.5, but in two's complement that gets rounded down to -2. The same happens when you divide -1 by 2, which should be -0.5, but that gets rounded down to -1 and you're stuck with -1 no matter how much you keep shifting... there will never be negative 0.


Top
 Profile  
 
PostPosted: Sat Dec 08, 2018 9:30 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 7632
Location: Canada
tokumaru wrote:
Yeah, an arithmetic right shift will shift the most significant bit right, but also preserve it as the most significant bit.

This instruction doesn't exist on the 6502. There is "arithmetic shift left" (ASL) and "logical shift right" (LSR), both of which are the same as rotate (ROL/ROR) if carry was zero.

There is no sign preserving right shift, AFAIK, you have to manually move the sign to carry before starting with ROR. Samophlange's LDA/CMP is a valid way to load carry with the sign. Could also LDA/ROL for the same result in one less byte.


Top
 Profile  
 
PostPosted: Sat Dec 08, 2018 9:42 pm 
Offline
User avatar

Joined: Thu Mar 31, 2016 11:15 am
Posts: 533
illegal opcode ARR #$FF is pretty close to being a sign-preserving right shift. At least when doing multiple shifts it is.

To round up, add N-1 to the value before shifting, where N is the amount you're dividing by.


Top
 Profile  
 
PostPosted: Sat Dec 08, 2018 10:13 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 11434
Location: Rio de Janeiro - Brazil
rainwarrior wrote:
This instruction doesn't exist on the 6502.

I didn't say it did, I was just explaining how the operation he implemented in several 6502 instructions worked.


Top
 Profile  
 
PostPosted: Sat Dec 08, 2018 10:30 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 7632
Location: Canada
pubby wrote:
illegal opcode ARR #$FF is pretty close to being a sign-preserving right shift. At least when doing multiple shifts it is.

Just to fully clarify, ARR appears to be:

1. Overflow (V) is set as if an ADC of: (A & #immediate) + #immediate ?
2. Result is: AND A with #immediate, followed by ROR
3. Carry (C) is set from bit 6 of result.
4. Zero/Negative (Z/N) from result.

So you still need to load the carry with sign before starting the shifts, but if you're doing multiple shifts on a single byte ARR #-1 can keep putting the sign back into the carry after each shift.

Apparently only helps if you need to shift more than once. Looks like this:
Code:
; value to be shifted already in A
CMP #$80 ; load sign into carry
ARR #$FF ; signed /2
ARR #$FF ; signed /4
ARR #$FF ; signed /8
ROR ; signed /16
; note that the last shift in the chain can be optimized as a ROR to save a byte.


(ARR is illegal opcode $6B.)


Last edited by rainwarrior on Sat Dec 08, 2018 10:47 pm, edited 1 time in total.

Top
 Profile  
 
PostPosted: Sat Dec 08, 2018 10:39 pm 
Offline

Joined: Wed Nov 30, 2016 4:45 pm
Posts: 147
Location: Southern California
We had basically the same conversation on 6502.org, at http://forum.6502.org/viewtopic.php?f=2&t=5317 . Various code suggestions were made there.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources


Top
 Profile  
 
PostPosted: Mon Jan 07, 2019 9:54 pm 
Offline
User avatar

Joined: Sun Apr 08, 2018 11:45 pm
Posts: 46
Location: Southern California
Thanks to all the folks in this thread (and re-reading that article on 6502.org several times) I've got some good general purpose math routines and I'm slowly changing some game objects over to have some nicer movement characteristics. :D
Is there a clever/compact way to see if two variables have the same sign? The only way I can think of involves ANDing with %10000000 into two temporaries and comparing those, but it seems like there should be some way to use the bit 7 "negative flag".


Top
 Profile  
 
PostPosted: Mon Jan 07, 2019 10:00 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 7632
Location: Canada
AND, ORA, and EOR all set the sign flag with bit 7 of the result, which can be useful for stuff like this.

Comparing value in A to variable "v":
Code:
EOR v
; sign bit will be 0 if the signs match, 1 if they differ

AND v
; sign bit will be set if both signs are negative

ORA v
; sign bit will be clear if both signs are positive


It's very often useful to store bit flags in the high bit, for this reason. A lot of instructions have "easy" access to it. (Also note that ROR/ROL make it easy to pass the the sign in/out of the carry flag too.)

Bit 6 is also convenient just for the BIT instruction, which can test it directly and puts the result in the overflow flag V... which is weird and special to that one instruction, but pretty handy especially for testing some hardware registers.


Top
 Profile  
 
PostPosted: Mon Jan 07, 2019 10:50 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 21695
Location: NE Indiana, USA (NTSC)
Bit 6 and 0 are only slightly less convenient than bit 7. Even in indexed or indirect contexts, where you can't bit, you can still send bit 6 to the N flag using asl a or bit 0 to the C flag using lsr a.

_________________
Pin Eight | Twitter | GitHub | Patreon


Top
 Profile  
 
PostPosted: Mon Jan 07, 2019 11:00 pm 
Offline
User avatar

Joined: Wed Apr 02, 2008 2:09 pm
Posts: 1289
Just to get a little meta, it might be worth looking into the overflow flag if you're not super familiar with it. Some cases where I used to want to check for same sign were helped by better understanding of the overflow flag. That's not to say using the eor is bad, just that there might be something better for the longer term goal sometimes.

_________________
https://kasumi.itch.io/indivisible


Top
 Profile  
 
PostPosted: Tue Jan 08, 2019 12:32 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 11434
Location: Rio de Janeiro - Brazil
samophlange wrote:
Is there a clever/compact way to see if two variables have the same sign? The only way I can think of involves ANDing with %10000000 into two temporaries and comparing those, but it seems like there should be some way to use the bit 7 "negative flag".

You don't need to isolate the bits or use any temporaries for this. Just EOR one value with the other directly and the N flag of the result will give you the answer. The result of EOR is 0 if both bits are equal, or 1 if they differ. So you can simply do this:

Code:
  lda Variable0
  eor Variable1
  bmi DifferentSigns
SameSign:
  ;(...)
DifferentSigns:
  ;(...)

Bitwise operations like EOR, AND and OR between two values only operate in bits at the same position in their respective bytes, so you don't need to isolate the bits of interest out of fear that the other ones might influence the result in any way. You only need to isolate the result, if the CPU doesn't do it for you automatically (as it does by copying bit 7 to the N flag).


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 41 posts ]  Go to page Previous  1, 2, 3

All times are UTC - 7 hours


Who is online

Users browsing this forum: MSN [Bot] and 6 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group