 Site Navigation [ News | Our Software | Calculators | Programming | Assembly | Downloads | Links | Cool Graphs | Feedback ]
 Main    Site News Our Software Legal Information Credits Calculators    Information C Programming Introduction to C Keyboard Input Graphics Intro Slider Puzzle 1 Functions Pointers Dynamic Memory Slider Puzzle 2 Structures Bit Manipulation Part I Part II Part III Advanced Pointers File I/O Graduate Review Assembly Downloads Miscellaneous    Links Cool Graphs Feedback Form ## TIGCC Programming Lessons

### Lesson 8: Bit Manipulation

Step 5 - The Other Bitwise Operations: OR, XOR, and NOT

There are several other kinds of bitwise operations, so I hope you liked AND, because here come even more. Hopefully, now that you are acquainted with the most common bitwise operator, the other ones will be easier to learn and understand.

The next bitwise operator we need to discuss is the bitwise OR. Bitwise OR is very similar to bitwise AND, but instead of returning true only when both bits are true, bitwise OR returns true if either bit is true. Let's look a small example so you can see how it works in general:

```   0b0011101001011011
OR 0b1100010111010010
------------------
0b1111111111011011```

I know the example is very abstract, but it is useful for demonstrating the logic side of the operation. Remember that bitwise means 'bit by bit'. So we perform the test bit by bit on every bit in our source and destination, and the result is the bits strung together.

The most common use you will have for bitwise OR will be masked sprites, but I don't want to delve into that right now, because it would take a long time to explain the concept. We'll come back to bitwise OR later on. Just make sure you understand how the bits get changed during an OR operation. You won't have use of this until later, but the bitwise OR operation in C is represented by the single pipe character, |. So, 0x3A5B | 0xC5B2 would perform the OR operation we did in the example.

The next bitwise operation is called bitwise XOR, also known as eXclusive OR. Remember that OR sets a bit in the result to be true if either bit is set. Well, exclusive or sets a bit in the result if either one of the bits are set, but not both. Let's look at a quick example:

```    0b1001110110001001
XOR 0b0001111001101110
------------------
0b1000001111100111```

This is again very abstract, but it's important to understand how the bitwise operators work. The most common use you will probably have for XOR is unmasked sprites. We have already used unmasked sprites, so you already know how they work a little. Now you can see how they work. The XOR operation takes the pixels on the screen, and the pixels from your sprite. The result is what we put on the screen.. Knowing this, we can see exactly how unmasked sprites work, and why drawing them and erasing them is the same.

If we have an area on the screen which is blank, the pixels will be all zeros, so when we XOR the sprite to the blank screen, the entire area of the sprite will be drawn on the screen, because the 1's on the sprite will be the only 1's in our XOR operation, making them the exclusive bits that will be set in the result. And, when we go to erase our sprite, the sprite's 1's will interfere with the 1's from the original sprite we drew on the screen, setting all the bits back to zero. This also shows you why unmasked sprites are only good when you don't need background, and why they are the simpler form of sprites. The bitwise XOR operation in C is represented by the single caret ^. So, to perform the operation we did in the example in C, we would do this: 0x9D89 ^ 0x1E6E.

The last bitwise operation we should take a look at is bitwise NOT. This last operation simply sets all the bits as the inverse of whatever they are. All the 1's become 0's and all the 0's become 1's. This is useful in many circumstances. When we talk about masked sprites, we will see how using bitwise not makes for an easy way to define inverse bit masks, but since we aren't talking about that yet, let's go into a topic we do have use for: the _rowread() function.

Remember in our last example, we used _rowread() to read a row of the keyboard. We needed to create an inverse mask of the keyboard row we wanted to read. To do that, we would take the row we wanted, and subtract it from the value 0xFFFF, the highest possible short integer value. This method is a little bulky though. It requires some extra work on our part, and why should we have to do that? We are using a computer after all. Shouldn't it take care of this arithmetic stuff for us? Well, it can. Remember that bitwise NOT sets all the bits to its inverse, an an inverse bit mask is just what we need.

The ESC row on the TI-89 is row 7, corresponding to the 6th bit in the matrix. So, the 6th bit would be represented by the hex number 0x0040. But that's not the number we need to use for _rowread(), because _rowread() requires an inverse mask, and we only have a mask. But we can use bitwise NOT to our advantage here. Instead of subtracting 0x0040 from 0xFFFF, we can just use the bitwise NOT of 0x0040. Bitwise NOT in C is represented by the ~ tilde character. Let's take a look at an example:

`enum KeyboardRows89 {ESCROW = ~0x0040, ARROWROW = ~0x0001};`

There are probably better uses for bitwise NOT, but it does save us a step or two in our programming.

Step 6 - Bit Shifting

We have almost covered all the topics related to bit manipulation, but there is still one very important topic that remains. Bit shifting. Bit shifting is the process of moving the places of the bits one or more places. That explanation doesn't really tell you much about bit shifting though, so let's try an example instead.

Shift Right 2 places: 0b0111001101110110 = 0b0001110011011101

Did you see what happened there? Probably not, so let's go over it. I shifted the bit places two positions to the right. This means the 2 right most bits (the bits on the right end, or the least significant bits) have been shifted out completely. They are gone. All the bits that were to the left of those initial right two bits are now two bit positions to the right. And in the first two bit positions, we have 0's. This is what happens when we shift bits. If we shift right, the lowest bits get lost, and the upper bits get new zeros. When we shift left, just the oppose, the lowest bits get new zero's and the upper bits get lost.

```unsigned int mask = 0x8000;
unsigned int mapRow = 0xF81C;	// this would be a function argument in real code
short int position = 8;	// find the 9th position. This would be an argument too...

// shift the mask right by the position

if (mask & mapRow) {
// position is occupied...
}```

The right shift operator is >> double greater-than, and << double less-than for left shift. The shift goes in the direction the "arrows are pointing". I know they don't look much like arrows, but just follow the point, or reread this lesson if you forget. Or better yet, read the TIGCC docs about C operators, cause it covers this too.

I think you can see how useful this would be in a game for testing positions. It has other uses too, but this is a very common use.

Step 7 - Bit Manipulation in Action

Our last program went a long way towards working something real with bit manipulation (among the other concepts we've learned), but we can go even further and add background to our little program now that we have added bit shifting.

So, start TIGCC. Create a new project and a new C Source File called bitmanip. Modify the file so that it looks like this:

bitmanip.c

```#include <tigcclib.h>
#include "bitmanip.h"

inline void drawBlock(POSITION pos) {
Sprite8(pos.x*BLOCK_WIDTH,pos.y*BLOCK_HEIGHT,BLOCK_HEIGHT,block,LCD_MEM,SPRT_XOR);
}

inline void eraseBlock(POSITION pos) {
drawBlock(pos);
}

inline void moveBlock(POSITION oldPosition, POSITION newPosition) {
eraseBlock(oldPosition);
drawBlock(newPosition);
}

void move(POSITION *pos, short int direction) {
POSITION oldPosition = *pos;

switch (direction) {
case UP:
// if we can move up, then do so
if (!isWall((POSITION){pos->x,pos->y-1})) {
pos->y--;
moveBlock(oldPosition,*pos);
}
break;
case DOWN:
// if we can move down, then do so
if (!isWall((POSITION){pos->x,pos->y+1})) {
pos->y++;
moveBlock(oldPosition,*pos);
}
break;
case LEFT:
// if we can move left, then do so
if (!isWall((POSITION){pos->x-1,pos->y})) {
pos->x--;
moveBlock(oldPosition,*pos);
}
break;
case RIGHT:
// if we can move right, then do so
if (!isWall((POSITION){pos->x+1,pos->y})) {
pos->x++;
moveBlock(oldPosition,*pos);
}
break;
}
}

void getKeyMasks(short int *keys, short int calc) {
// find the correct key masks based on which calculator we have
if (calc == 0) {        // do we have a TI-89
keys = 0x0001;   // bit 0
keys = 0x0004;   // bit 2
keys = 0x0002;   // bit 1
keys = 0x0008;   // bit 3
} else {            // then we must have a TI-92+
keys = 0x0020;   // bit 5
keys = 0x0080;   // bit 7
keys = 0x0010;   // bit 4
keys = 0x0040;   // bit 6
}
}

// slow the program down
void delay(void) {
short int loop = 1800, randNum;

// generate random numbers to slow down the program...
while (loop-- > 0) {
randNum = rand() % loop;
}
}

short int quit(short int calc) {
if (calc == 0) {    // test for TI-89 ESC key
if (_rowread(TI89_ESCROW) & TI89_ESCKEY) {
return 1;
}
} else {        // test for TI-92+ ESC key
if (_rowread(TI92_ESCROW) & TI92_ESCKEY) {
return 1;
}
}

return 0;
}

short int isWall(POSITION pos) {
unsigned long int mask = 0x80000 >> pos.x, position = map[pos.y];

// if mask and position collide, we hit a wall
if (mask & position) {
return 1;
}

// otherwise, we didn't
return 0;
}

void drawMap(void) {
short int row, column;
unsigned long int mask, position;

// clear the screen before drawing
ClrScr();

// loop through the map array
for (row = 0; row < MAP_ROWS; row++) {
// get the positions for this row
position = map[row];

// reset the bit mask

// loop through the column to see where in the row we need to draw blocks
for (column = 0; column < MAP_COLUMNS; column++) {
// shift the bit mask

// check the position, if set, draw the block
if (position & mask) {
drawBlock((POSITION){column,row});
}
}
}
}

void _main(void) {
short int keys;
short int calc = CALCULATOR, key;
INT_HANDLER interrupt1 = GetIntVec(AUTO_INT_1);
INT_HANDLER interrupt5 = GetIntVec(AUTO_INT_5);
POSITION pos = {2,2};

// replace auto-interrupts 1 and 5 so they don't interfere with keyboard reading
SetIntVec(AUTO_INT_1,DUMMY_HANDLER);
SetIntVec(AUTO_INT_5,DUMMY_HANDLER);

// get the correct key masks based on which calculator we have. The TI-89
// has a different keyboard mapping than the TI-92+

// draw the map on the screen
drawMap();

// draw the block on the screen at our initial position
drawBlock(pos);

// until the user presses ESC
while (!quit(calc)) {

// check for UP arrow
if (key & keys[UP]) {
move(&pos,UP);
}

// check for LEFT arrow
if (key & keys[LEFT]) {
move(&pos,LEFT);
}

// check for DOWN arrow
if (key & keys[DOWN]) {
move(&pos,DOWN);
}

// check for RIGHT arrow
if (key & keys[RIGHT]) {
move(&pos,RIGHT);
}

// slow the program down
delay();
}

// restore auto-interrupts
SetIntVec(AUTO_INT_1,interrupt1);
SetIntVec(AUTO_INT_5,interrupt5);
}```

Now create a new C Header File named bitmanip. Modify the file so that it looks like this:

bitmanip.h

```#ifndef _BITMANIP_H
#define _BITMANIP_H

/* Constants */
enum MapDimensions {MAP_ROWS = 19, MAP_COLUMNS = 20};
enum BlockConstants {BLOCK_HEIGHT = 5, BLOCK_WIDTH = 8};

enum ArrowKeys {UP,DOWN,LEFT,RIGHT};
enum KeyMatrix {TI89_ESCROW = ~0x0040, TI89_ESCKEY = 0x0001,
TI92_ESCROW = ~0x0100, TI92_ESCKEY = 0x0040,
ARROW_ROW = ~0x0001};

/* Structure Definitions */

typedef struct {
unsigned short int x : 8, y : 8;
} POSITION;

/* Sprite Definitions */

static unsigned long int map[] = {0xFFFFF,0x80001,0x80001,0x80001,0x80401,0x80401,0x80401,0x80401,
0x80401,0x87FC1,0x80401,0x80401,0x80401,0x80401,0x80401,0x80001,
0x80001,0x80001,0xFFFFF};

static unsigned char block[] = {0xFF,0xFF,0xFF,0xFF,0xFF};

/* Function Proto-types */

inline void drawBlock(POSITION);
inline void eraseBlock(POSITION);
inline void moveBlock(POSITION, POSITION);

void move(POSITION *, short int);

void getKeyMasks(short int *, short int);
void delay(void);
short int quit(short int);

short int isWall(POSITION);
void drawMap(void);

void _main(void);

#endif```

Step 7a - Compile and Run the Program

Save the files and build the project. Send the program to TiEmu and run it. It will look something like this:  Step 7b - Program Analysis

This program is very similar to the last one, but we have added a new feature, the background map. This let's us move a sprite around the screen, but keep track of the background area so we know where we can move the sprite, and where we cannot. This would be good for any kind of game that moved a character along a screen, especially if they have some background obstacles the character cannot pass through (mountains, rivers, oceans, etc.)

Since this program is so similar to the last program, we will only work on analyzing the differences in the programs. Let's start in the _main() method, as always.

```// draw the map on the screen
drawMap();```

The first change is that we have to actually draw the map background on the screen as part of the initialization process. The drawMap() function is the first place we use bit shifting.

```void drawMap(void) {
short int row, column;
unsigned long int mask, position;

// clear the screen before drawing
ClrScr();

// loop through the map array
for (row = 0; row < MAP_ROWS; row++) {
// get the positions for this row
position = map[row];

// reset the bit mask

// loop through the column to see where in the row we need to draw blocks
for (column = 0; column < MAP_COLUMNS; column++) {
// shift the bit mask

// check the position, if set, draw the block
if (position & mask) {
drawBlock((POSITION){column,row});
}
}
}
}```

Okay, the drawMap() function is not too difficult, but it uses some tricks that may not seem so obvious, until you see them in actual code. The draw map uses two counters to loop through all the rows and columns (row x column = map array). Then of course, we have our bit mask and the position. The first thing we do in the outer loop is to grab the position, which is the map row. The mask represents the column position. Since the mask will be shifting before the first check, we set the initial mask to one bit left of the first position. We could have done the shifting after we check the position, it's the same either way. The >>= operator is just like the += or -= or any other ?= operators, it performs the left operator, then assigns the result back to the left side variable. So, mask >>= 1 will shift our bit mask 1 position to the right.

Finally, if our bit mask (properly shifted) and our position (map row) AND together to produce a TRUE result, we draw a block on the screen at the current position. The only odd thing about this is our new use of the cast operator. Remember that C can cast almost anything to anything else. In this case, we want have our two integers for our x and y positions, but the drawBlock() function takes a POSITION structure. So, to get the integer variables into a structure, we can cast them into a structure by using the type cast operator. It's just the same as initializing a structure, but we use the cast operator in front of it. So (POSITION){column,row} will create a POSITION structure on the fly using the data from the column and row variables for the x and y member variables, respectively.

The last difference in the program is in the move() function. Since we have to check to see if we hit walls now, we had to make some minor updates to the program, naturally.

```void move(POSITION *pos, short int direction) {
POSITION oldPosition = *pos;

switch (direction) {
case UP:
// if we can move up, then do so
if (!isWall((POSITION){pos->x,pos->y-1})) {
pos->y--;
moveBlock(oldPosition,*pos);
}
break;
case DOWN:
// if we can move down, then do so
if (!isWall((POSITION){pos->x,pos->y+1})) {
pos->y++;
moveBlock(oldPosition,*pos);
}
break;
case LEFT:
// if we can move left, then do so
if (!isWall((POSITION){pos->x-1,pos->y})) {
pos->x--;
moveBlock(oldPosition,*pos);
}
break;
case RIGHT:
// if we can move right, then do so
if (!isWall((POSITION){pos->x+1,pos->y})) {
pos->x++;
moveBlock(oldPosition,*pos);
}
break;
}
}```

The function is very similar to the old function, but instead of checking the boundaries of the screen which we did in the old version, we check to see if we hit any walls. Normally, we would have to check for screen boundaries, too, but our particular map for this program has a surrounding barrier on all sides, so we only need to make sure it didn't hit a wall. To do that, we use the isWall() function, which returns 1 (true) if we hit a wall, or 0 (false) if we didn't hit a wall. If the new position will intersect a wall, we don't change the position at all, but if it won't, we change the position and then move the block sprite.

```short int isWall(POSITION pos) {
unsigned long int mask = 0x80000 >> pos.x, position = map[pos.y];

// if mask and position collide, we hit a wall
if (mask & position) {
return 1;
}

// otherwise, we didn't
return 0;
}```

Okay, the isWall() function tells us is a position is in a wall or not. Our mask variable is our column, and our position is the map row. Since we are checking against the position structure we are given, the map row will be the node in the map array of the Yth position, and the column we need to check will be the bit shift x from our starting position 0x80000. If our mask AND our position intersect, then we hit a wall, so we should return 1 (true), otherwise we return 0 (false).

```enum KeyMatrix {TI89_ESCROW = ~0x0040, TI89_ESCKEY = 0x0001,
TI92_ESCROW = ~0x0100, TI92_ESCKEY = 0x0040,
ARROW_ROW = ~0x0001};```

The last thing I want to show you is our use of the bitwise NOT operator to do the inverted bit masks for our keyboard matrix rows for use with the _rowread() function. The ESC row, which is the 7th row (bit 6) needs to be inverted so we can use it with the _rowread() function. We use the ~ bitwise NOT operator to have it perform the inversion for us. This is just one of the little nice things that C takes care of for us.

Step 8 - Conclusion

Bit operations are one of the most powerful operations in C. They are very useful in checking masks and often provide speed bonuses.

Lesson 8: Bit Manipulation