EOR: Some Special Uses
In my own personal, ongoing quest for doing things quicker or more RAM-efficiently with 6502 assembly on the Commodore 64, some time ago I blundered into some nice little hacks with the EOR instruction, the "Exclusive OR".
Some of my favourites are:
- A tiny EOR-based switch aka "alternator" for frame-skipping in raster interrupts.
- Using EOR for faster subtraction.
- Using EOR for faster addition.
Lets consider each of them in turn:
1. EOR-based alternator: At some point in many 6502 coding scenarios, you will probably want to perform certain tasks only on every other frame; it could be some game AI, it could be something like Toggleplexing, an audio effect, a scroll event or whatever; the key thing is that you need to do it every other frame.
For this, you could do as follows (which has probably been used by many coders since the 1980s, so it's not my invention!) inside one interrupt handler, so that it fires once every frame (i.e. screen refresh):
BNE ODDFRAME ; Branch to ODDFRAME every "odd" frame, whereas this BNE is ignored on every "even" frame
; EVENFRAME code goes here
All you have to do when setting this up at the start of the program is to ensure the variable ZPTOGGLE = either 0 or 1 and EOR will invert that value every frame, producing a 0,1,0,1,0,1,0,1,0 cycle ad infinitum.
SPECIAL NOTE: I like to use another way to perform the toggle logic that saves 1 cycle on both odd and even paths compared to the above, but it requires the use of self-modifying code and consumes more RAM for the logic... this is scheduled for inclusion in the next Newsletter for subscribers.
2. EOR for faster subtraction: Normally you would subtract using SEC and SBC, such as per the following example:
SBC BITTABLE,Y ; where BITTABLE,Y is known to hold only values less than #%00011111
That takes 2 + 2 + 4* cycles = 8-9 cycles, the actual number depending on whether or not the page boundary is crossed by the SBC,Y operation; and if we say, by way of illustration, that the value in BITTABLE,Y = #%00001111 (15 in decimal), the result will be #%00010000, i.e, 31 - 15 = 16.
So if we can safely predict the range of the value being subtracted, we could use EOR to do the subtraction like this:
EOR #%00011111 ; Shorthand for subtracting BITTABLE,Y from #%00011111
The same calculation (with the same result, obviously!) now takes 4* + 2 cycles = 6-7 cycles, the actual number depending on whether or not the page boundary is crossed by the LDA,Y operation, with the extra bonus of the carry flag remaining unaltered by the calculation!
Again, the idea of using EOR for this kind of subtraction is not my invention and it's probably impossible to know who did it first, but it's slick and saves 2 precious CPU cycles and 1 byte of RAM from the standard way of subtracting.
(Incidentally, this forms part of the landscape damage encoding routine in Parallaxian, in which trees set on fire by bombing are still on fire next time they scroll on to the screen).
3. EOR for faster addition: Just as you can use EOR for fast subtraction if the constraints of that subtraction are first known and understood, so you can also use it for some fast addition, with the same fundamental proviso.
For example, let's say you want to add any number less than #$F0 (in decimal, 128 or, in binary #%10000000) to #$F0; normally, you would use CLC and ADC to do the following (we should keep it all in binary to help understand what's happening with the various bits):
That gives a result of #%10001010 (138 in decimal) in the A-reg and takes 2 + 2 + 2 = 6 cycles, but consider that the following will give you the same result:
...which puts #%10001010 (138 in decimal) in the A-reg but takes only 2 + 2 = 4 cycles, with the saving still applying over different addressing modes if you replace like with like and, as with the EOR subtraction, you walk out of the calculation with the carry flag unaffected!
Of course, that's only the tip of the iceberg in terms of what can be done with EOR; for example, you can use it to save space in the VIC bank if you have a sprite that has a flickering flame such as that used by Parallaxian's "Backfire" enemy - the flickering flame is highlighted in yellow below:
So instead of keeping the full definitions for the craft with and without the flame showing, you only need one and use EOR to manually draw / clear the sprite data for the flame
on alternating frames.
Another nice use for EOR I came across was where you can use it to obfuscate code, as per the final example on this Dustlayer post about Bit Manipulation.
Finally, there are some helpful generic, non-C64-related tools online that will allow you to perform tests using the big 3 logical operators of AND, ORA and EOR (which sometimes is known as XOR), such as this one: bitwise-calculator.
Illegal Opcode SAX/AXS: A Practical Use
PS: Don't forget to check the home page regularly for more articles like this.
And of course, kindly subscribe to my YouTube channel!
Last of all, for additional short snippets of content, check out the posts on my Ko-fi page.
Help Make Parallaxian Happen!
...and get special perks!
Progress on Parallaxian has slowed down since summer 2021 for several reasons, one of which has been the very low level of support from
the C64 scene which has made it difficult to continue justifying to my family the long hours of hard work a project as complex as this requires.
Now, I understand these are difficult times and I admit I am not entitled to any support at all, but it really does encourage me to continue developing this sensational game when you make a Paypal donation.
And as a special thank you, all who do this can enjoy the following perks:
- Your name credited in the game (unless you opt out of it if you have the same kind of incognito hermit tendencies I do).
- Access to the ongoing beta-testing of the game (unless you would prefer not to see it before its release date).
- The finished game on media (e.g. cartridge) for FREE one week before its release.