Gamasutra is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Gamasutra: The Art & Business of Making Gamesspacer
View All     RSS
September 17, 2019
arrowPress Releases







If you enjoy reading this site, you might also want to check out these UBM Tech sites:


 

Retro Insectivores: Finding and Eliminating Bugs in NES Development

by James Deighan on 09/04/19 10:44:00 am   Featured Blogs

1 comments Share on Twitter    RSS

The following blog post, unless otherwise noted, was written by a member of Gamasutra’s community.
The thoughts and opinions expressed are those of the writer and not Gamasutra or its parent company.

 

If you have ever engaged in programming, then you know about bugs. If bugs didn't bother us, the development process would be faster and more enjoyable. But these bugs are just waiting for the moment to corrupt our code and spoil our timelines and creative flows. Fortunately, there are many tools and strategies for eliminating bugs - even for retro programmers.

Debugging Tools

One of  the best ways to debug your code is to use a debugger. Some of the FCEUX and Mesen emulators have a built-in debugger which can interrupt program execution at any time in order to check the code for operability.

FCEUX Debugger

It is worth saying that this way is more suitable for advanced programmers who use assembly language. But since we are newbies, we will use the C language (cc65). Of course, the compiler will play by its own rules, and it will be difficult for us to navigate the machine code compiled from the C language.

FCEUX Hex Editor

Suppose we need to watch for some variable or array. Add the following parameter to your linker option (ld65): -Ln labels.txt

When the project is compiled, you will find the file labels.txt in your project folder. Just open it with any text viewer and look for the name of the variable you need to watch.

(Note: if you declare a static variable, it will not be included in this list. Therefore use unsigned char playerX; instead of static unsigned char playerX)

Debugger Labels

Now we know the address of the required variable. Not bad. Let's find it in the debugger. Start your ROM with the FCEUX emulator. In the “Debug menu”, click on the “Hex Editor” item, in the window that opens, press ctrl + g, and enter the address of your variable:

Find Tool

Click OK and the cursor will be moved to the address where the variable is located. Let's look at this:

Meating Hex Editor

This can be useful to check if the array is filled correctly, or to watch changes in specific variables. It also makes you feel a bit Big Brotherish, surveilling your code like this.

Be sure to check the FCEUX emulator Debug menu for other useful tools, like PPU Viewer, Name table Viewer, and much more.

Streamlining the Debug Process

What if you don’t want to run the debugger each time you check for a variable? An advanced method is to write a subroutine that will display any value on the screen. Let's try to use the score in the HUD to display the player's position on the Y axis:

Meating Macro

Works like a charm! 

Doug Fraker, a retro coder and owner of the nesdoug blog, provides a similar method for using an on-screen visualization for debugging purposes. The following subroutine creates a grey line on the screen which visually indicates CPU usage:

// void gray_line(void);
// For debugging. Insert at the end of the game loop, to see how much frame is left.
// Will print a gray line on the screen. Distance to the bottom = how much is left.
// No line, possibly means that you are in v-blank.
 
_gray_line:
 
     

If you have ever engaged in programming, then you know about bugs. If bugs didn't bother us, the development process would be faster and more enjoyable. But these bugs are just waiting for the moment to corrupt our code and spoil our timelines and creative flows. Fortunately, there are many tools and strategies for eliminating bugs - even for retro programmers.

Debugging Tools

One of  the best ways to debug your code is to use a debugger. Some of the FCEUX and Mesen emulators have a built-in debugger which can interrupt program execution at any time in order to check the code for operability.

FCEUX Debugger

It is worth saying that this way is more suitable for advanced programmers who use assembly language. But since we are newbies, we will use the C language (cc65). Of course, the compiler will play by its own rules, and it will be difficult for us to navigate the machine code compiled from the C language.

FCEUX Hex Editor

Suppose we need to watch for some variable or array. Add the following parameter to your linker option (ld65): -Ln labels.txt

When the project is compiled, you will find the file labels.txt in your project folder. Just open it with any text viewer and look for the name of the variable you need to watch.

(Note: if you declare a static variable, it will not be included in this list. Therefore use unsigned char playerX; instead of static unsigned char playerX)

Debugger Labels

Now we know the address of the required variable. Not bad. Let's find it in the debugger. Start your ROM with the FCEUX emulator. In the “Debug menu”, click on the “Hex Editor” item, in the window that opens, press ctrl + g, and enter the address of your variable:

Find Tool

Click OK and the cursor will be moved to the address where the variable is located. Let's look at this:

Meating Hex Editor

This can be useful to check if the array is filled correctly, or to watch changes in specific variables. It also makes you feel a bit Big Brotherish, surveilling your code like this.

Be sure to check the FCEUX emulator Debug menu for other useful tools, like PPU Viewer, Name table Viewer, and much more.

Streamlining the Debug Process

What if you don’t want to run the debugger each time you check for a variable? An advanced method is to write a subroutine that will display any value on the screen. Let's try to use the score in the HUD to display the player's position on the Y axis:

Meating Macro

Works like a charm! 

Doug Fraker, a retro coder and owner of the nesdoug blog, provides a similar method for using an on-screen visualization for debugging purposes. The following subroutine creates a grey line on the screen which visually indicates CPU usage:

// void gray_line(void);
// For debugging. Insert at the end of the game loop, to see how much frame is left.
// Will print a gray line on the screen. Distance to the bottom = how much is left.
// No line, possibly means that you are in v-blank.
 
_gray_line:

 

If you have ever engaged in programming, then you know about bugs. If bugs didn't bother us, the development process would be faster and more enjoyable. But these bugs are just waiting for the moment to corrupt our code and spoil our timelines and creative flows. Fortunately, there are many tools and strategies for eliminating bugs - even for retro programmers.

Debugging Tools

One of  the best ways to debug your code is to use a debugger. Some of the FCEUX and Mesen emulators have a built-in debugger which can interrupt program execution at any time in order to check the code for operability.

FCEUX Debugger

It is worth saying that this way is more suitable for advanced programmers who use assembly language. But since we are newbies, we will use the C language (cc65). Of course, the compiler will play by its own rules, and it will be difficult for us to navigate the machine code compiled from the C language.

FCEUX Hex Editor

Suppose we need to watch for some variable or array. Add the following parameter to your linker option (ld65): -Ln labels.txt

When the project is compiled, you will find the file labels.txt in your project folder. Just open it with any text viewer and look for the name of the variable you need to watch.

(Note: if you declare a static variable, it will not be included in this list. Therefore use unsigned char playerX; instead of static unsigned char playerX)

Debugger Labels

Now we know the address of the required variable. Not bad. Let's find it in the debugger. Start your ROM with the FCEUX emulator. In the “Debug menu”, click on the “Hex Editor” item, in the window that opens, press ctrl + g, and enter the address of your variable:

Find Tool

Click OK and the cursor will be moved to the address where the variable is located. Let's look at this:

Meating Hex Editor

This can be useful to check if the array is filled correctly, or to watch changes in specific variables. It also makes you feel a bit Big Brotherish, surveilling your code like this.

Be sure to check the FCEUX emulator Debug menu for other useful tools, like PPU Viewer, Name table Viewer, and much more.

Streamlining the Debug Process

What if you don’t want to run the debugger each time you check for a variable? An advanced method is to write a subroutine that will display any value on the screen. Let's try to use the score in the HUD to display the player's position on the Y axis:

Meating Macro

Works like a charm! 

Doug Fraker, a retro coder and owner of the nesdoug blog, provides a similar method for using an on-screen visualization for debugging purposes. The following subroutine creates a grey line on the screen which visually indicates CPU usage:

// void gray_line(void);
// For debugging. Insert at the end of the game loop, to see how much frame is left.
// Will print a gray line on the screen. Distance to the bottom = how much is left.
// No line, possibly means that you are in v-blank.
 
_gray_line:
 
   lda <PPU_MASK_VAR
   and #$1f ;no color emphasis bits
   ora #1 ;yes gray bit
   sta PPU_MASK
 
ldx #20 ;wait
 
@loop2:
 
   dex
   bne @loop2
   lda <PPU_MASK_VAR ;normal
   sta PPU_MASK
   rts

You can copy-paste this to your source, or include the nesdoug.h library in your project. Call this subroutine after your game cycle has been completed, and you will see this gray bar on the screen.

Meating Macro 2

It works, but I think I got another bug! I’ll get rid of it later. For now, let’s move on.

The Power of Macros

Macros can also be a useful tool for debugging. They can help you pinpoint the spot in your code that is fending off a bug infestation.

Let's create some macros that will give us some signals at the right time, like playing a sound or highlighting a zero palette with a necessary value. Here we have a few macros that change the zero palette to red, blue and random colors, and for playing a sound:

Sound Macro

How does it work? Suppose your project is successfully compiled, you run the emulator with your game, click the Start button and...

Meating Macro

It seems there is nothing here except the white screen. In addition, some emulators will tell you in the status bar: CPU jam! What do we do now?

First of all we have to localize the code where the error occurs. This is where my sound macro comes into play.

We know for sure that at least the main menu works, let's see what happens after it:

playMainMenu();

player.lives = 9;
points = 0;
gameFlags = 0;

while(current_level<7 && player.lives>0)

{

       set_world(current_world);

      debugSound;

      playCurrentLevel();

}

I have a suspicion that the game crashes on the execution of the set_world subroutine. Let's check it out. I will simply write the name of the macro in the next line after the subroutine I want to check.

We start the project and ... I hear a sound! So, this subroutine completed successfully, and we need to check next one: playCurrentLevel. Let’s move the debug macro below:

while(current_level<7 && player.lives>0)

{

       set_world();

       playCurrentLevel():

      debugSound;

}

I run the project again, and do not hear the sound. This means that my subroutine is not complete, and a failure is occurring inside it.

In these cases, open the listing of the subroutine in question and continue using this method until you narrow the range of where the bug could be hiding.

Macros that change the palette can also be useful for checking conditions. For example, our code performs a complex check of several conditions:

if ( (getTile(objX, objY+16) || collide16() ) || (objsOX[i] && objY>objsOX[i]))

{

       debugRed;

       objsSTATE[i]=THWOMP_SMASH;

       objY=objsY[i]-=4;

       objsFRM[i]=0;

      sfx_play(SFX_THWOMP_SLAM_DOWN,2);

}

f we switch the color of the palette here, we will see if our condition is fulfilled or not:

Macros and meat

It seems that this chicken is fine. But if the flag does not work, then one of the conditions is not met. In this case, check each of them separately, and perhaps you will find another creepy bug.

The Nuclear Option

Recently, I noticed that one of the ghosts exhibiting some suspicious behavior. Occasionally, they refused to attack the player. 

Take a look at this bug-enslaved ghost - it attacks only when the character is close to the center of the screen:

Bad Meating Ghost

No matter how much I looked at the code of this procedure, I could not understand where the bug was hidden, so I decided to take extreme measures and test the performance of this code in a modern development environment.

I took with me everything I needed: a map of the screen, an array with the attributes of metatiles, the code of the subroutine, and just pasted all this in Visual Studio 2017:

VisualStudio2017 Meating Code

Here, on the PC, this code worked exactly the same way. As it turned out, the bug was hiding in a procedure that fills the cache to find the obstacles between the player and the enemy. My array was not filled correctly. I'm fairly certain there should be 0 instead of 0x80.

Russian Code

Well, I will try to debug the code step by step to find out why this is happening.

VisualStudio2017 Meating Code

It's funny, but it seems like I performed the actions in the wrong sequence. Let's fix it and check array again!

Russian Code

It seems that now the array is filled correctly. So, I have only to fix the cc65 code, and compile the NES project once more.

 

 

So, modern development tools will be able to help debug your algorithms and get rid of bugs. 

Eat Bugs in Peace

Bugs are frustrating, and debugging can be too. Just stay calm, stay in control, and use every tool at your disposal to find and destroy these filthy insects. Your code, and your peace of mind, will feel much better.

 

Want more tips straight from the retro pros? Welcome to our Discord!

Get mad meat on The Meating page now!


Related Jobs

Daybreak Games
Daybreak Games — Austin, Texas, United States
[09.16.19]

Senior Engine Programmer
Daybreak Games
Daybreak Games — Austin, Texas, United States
[09.16.19]

Senior Server Programmer
Daybreak Games
Daybreak Games — Austin, Texas, United States
[09.16.19]

Senior Tools Programmer
Disbelief
Disbelief — Cambridge, Massachusetts, United States
[09.16.19]

Senior Programmer, Cambridge, MA





Loading Comments

loader image