My journey experimenting with 6502 assembly and CC65

Greetings!

A while ago I slowly started experimenting with 6502 assembly while I read a bit about the subject. After some tinkering around, I really got excited with the idea of creating a NES game.

I sketched some ideas and ended up with a fantasy roguelike(so original!) and choose to use CC65(a C compiler for machines with a 6502-compatible CPU).

However, I ended up dealing with some pitfalls during development, like: 2 axis map scrolling, random map generation… heck! I wasn’t even able to export the music from FamiTracker into the code.

It was a new experience and provided me a lot of epiphanies, but nearly all tools are designed for Windows(even the emulator with debugger) and such difficulties really slowed my other ideas.

I am going to move the project to C#/SDL2, trying to keep as much as possible the NES limitations (pallete, resolution, sound) and on a future resume the NES version.

Wisely using Bitwise Operators and Bit Manipulations

Heh… fancy title, isn’t it?

Low-level programming always fascinated me, I can’t put in words the epiphany that I experienced when I first wrote a set of instructions to divide an integer.  Moreover, I always had an interest in performance optimization.

Here I present some tips used to improve performance or reduce memory usage. Keep in mind that today’s modern compilers are smart enough to perform better optimizations in some cases and some of the techniques presented here are in fact slower on modern CPU architectures due to instructions being executed in parallel.

I hope you already understand logic gates and bitwise operations. The input will be in a pseudo-code followed by the output and binary representation in another block.

Even or Odd

This method is faster than modulo operation as it doesn’t uses division.

bool isOdd(int num)
{
   return num&1;
}
isOdd(7) returns 1

  00000111 <- 7
& 00000001 <- 1
----------
  00000001 <- 1

Forcing evaluations in if/elseif statements

If you are using AND(&&) and OR(||) operators with functions/methods you know that if the first or any subsequent fails(in AND case) or succeeds(in OR case) the other methods won’t execute. To get around that you can use bitwise operators.

//consider the return of the functions as boolean(0/1) and not an arbitrary integer
if (myFunc1()&myFunc2()&myFunc3)
{
// all three executed and returned true
}
else
{
// all three executed and at lease one returned false
}
myFunc1() returns 1
myFunc2() returns 0
myFunc3() returns 1

  00000001 <- 1
& 00000000 <- 0
& 00000001 <- 1
----------
  00000000 <- 0

//If AND(&&) was used, the myFunc3() would never be performed. The same idea can be used with OR(||) and |, but to execute the subsequent ones in case of the first succeed.

XOR Swap

Swap values between two int variables without a third one. Not recommended on modern systems(but still amazing!).

char a=5;
char b=3;
a=a^b;
b=b^a;
a=a^b;
  00000101 <- a=5
^ 00000011 <- b=3
----------
  00000110 <- a=6

  00000011 <- b=3
^ 00000110 <- a=6
----------
  00000101 <- b=5

  00000110 <- a=6
^ 00000101 <- b=5
----------
  00000011 <- a=3

Division and multiplication by powers of two

With bitshift you can divide or multiply by any power of two.

Swap values between two int variables without a third one. Not recommended on modern systems(but still amazing!).

char a=5<<1; // 5*2 or 5*(2^1)
char b=2<<3; // 2*8 or 2*(2^3)
char c=80>>4; // 80/16 or 80/(2^4)
  00000101 <- 5
      << 1
----------
  00001010 <- a=10

  00000010 <- 2
      << 3
----------
  00010000 <- a=16

  01010000 <- 80
      >> 4
----------
  00000101 <- a=5

Extracting Red, Blue and Green from RGB

You can use bitshift and & to isolate colors.

uint32_t color = 0x9C5052;
char red=(color>>16)&0xFF;
char blue=(color>>8)&0xFF;
char green;color&0xFF;
   100111000101000001010010 <- 10244178 / 0x9C5052
                      >> 16
---------------------------
                   10011100
                  &11111111
---------------------------
                   10011100 <- 156 or 0x9C

   100111000101000001010010 <- 10244178 / 0x9C5052
                       >> 8
---------------------------
           1001110001010000
                  &11111111
---------------------------
                   01010000 <- 80 or 0x50

   100111000101000001010010 <- 10244178 / 0x9C5052
                  &11111111
---------------------------
                   01010010 <- 82 or 0x52

Checking, inverting, setting and clearing the nth bit

You can use bitshift and & to isolate colors.

char num = 57;
char bit = 6; / nth bit defined as 6
//checking 6th bit
return 1&(num>>(bit-1));
//inverting 6th bit
return num^(1<<(bit-1));
//setting 6th bit
return num|(1<<(bit-1));
//clearing 6th bit
return num&~(1<<(bit-1));


//checking
   00111001 // 57
       >> 5 // shift 5 times
-----------
   00000001 
&  00000001
-----------
   00000001 // 6th bit is on

//inverting
   00000001 // 1
       << 5 // shift 5 times
-----------
   00100000 
^  00111001 
-----------
   00011001

//setting
   00000001 // 1
       << 5 // shift 5 times
-----------
   00100000 
|  00111001 
-----------
   00111001

//clearing
   00000001 // 1
       << 5 // shift 5 times
-----------
~  00100000 // reverses the bits
-----------
   11011111 
&  00111001 
-----------
   00011001

Some programming languages allocate one byte for a boolean, you can use this technique to treat an integer as an array of booleans or flags.

Conclusion

These are my favorite hacks and utilities using bitwise operations. Be careful since your code can become confusing and unreadable for your coworkers.

You can see more complex examples here. But I don’t recommend you using too extreme and obscure for the reasons mentioned above.