EOR: Some Special Uses
In my own personal, ongoing quest for doing things quicker or more RAM-efficiently with code, 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 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.
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
Interested in coding on the C64? Check out this Kindle e-book on Amazon (and yes, I get a tiny pittance if you buy via the banner below):
PS: Don't forget to check the home page regularly for more articles like this and visit the Everything64 Forum to comment further.
And of course, kindly follow me on Twitter and subscribe to my YouTube channel!
Help Make Parallaxian Happen
I would ask you if you could consider a small, recurring monthly donation (and depending on your tax situation, you might even be able to designate it as a charitable donation rather than let the taxman have it).
And don't worry, you can cancel at any time... but in the meantime, it would be a welcome contribution, however petite.
Oh, and as a special thank you, all who do this will be credited in the game (unless you opt out of it if you have the same kind of incognito hermit tendencies I do).