Algorithms, Assemblers, and IDEs

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Algorithms, Assemblers, and IDEs
by on (#179934)
Hello everyone! I have been a lurker on this site for a few years now, but finally registered today. As with most newbies here I have these lofty goals of developing my own NES games. I've read the Nerdy Nights, NESprgmn, NinTech, and Metopal tutorials ("I AM EXTRA") and feel I have an adequate understanding of the architecture and assembly language. One of the issues I keep running into, however is the availability of tools for game building, more specifically an IDE (Integrated Development Environment). It looks like there was some work with NESIDE and there are piecemeal tools such as YY-CHR, Tile Molester, Notepad++, NESASM3, and NESTICLE that have been recommended, but nothing that's all inclusive. I've looked into building my own IDE using C# and although I have made some progress (CHR and Background Builder works), I hit a road block when I got into the assembler portion of program. While some of the struggle is due to my lack of ASM language experience, most has to do with hardware timing, code optimization, and the compiler.

For example, recently I was trying to figure out how I could build a generic stack of PPU changes that can be popped off during the VBlank and be built outside of this time. This was my attempt at a solution:

Input Variables:

StackSize - 1 byte integer (0 to 255) that tracks how many elements are in the stack. (Assumed to be on Zero Page)
StartHiByte - 2 byte address that points to the start of stack for where the High Byte of the PPU address will be stored
StartLowByte - 2 byte address that points to the start of the stack where the Low Byte of the PPU address will be stored
StartValue - 2 byte address that points to the start of the stack where the Value Byte that will be stored at the PPU address

Algorithm:

Code:
LDA $2002        ; Reset Hi/Low Bit
LDX StackSize   ; Load Stack Size into X Register

NextLabel:
LDA StartHiByte, X;
STA $2006
LDA StartLowByte, X;
STA $2006
LDA StartValue, X;
STA $2007
DEX
BNE NextLabel:



By my estimate (and please correct me if I am wrong):

ROM Cost: 26 Bytes
Cycle Cost: 6 + 29 * StackSize

At 2200 cycles available to make PPU changes that gives me about 75 value changes per VBlank.

I understand that if the changes are ordered, such as with Sprite RAM, I can DMA more efficiently.

So my questions for everyone are:

1. How does everyone else manage their PPU changes and VBlank Timing? Am I even in the ballpark?
2. And is there a single repository of algorithms somewhere (such as nametable compression).
3. What one tool would make programming NES games easier for you?

Thank you!

[EDIT:] Grammar
Re: Algorithms, Assemblers, and IDEs
by on (#179937)
Lucradan wrote:
1. How does everyone else manage their PPU changes and VBlank Timing? Am I even in the ballpark?
2. And is there a single repository of algorithms somewhere (such as nametable compression).
3. What one tool would make programming NES games easier for you?


3. If I think I need some new tool I'll probably make it for myself, but the most useful things for me are: FCEUX, cc65 assembler, notepad++, GIMP, python, shiru's NES screen tool.

1. Where cycles matter, I generally try to predict them by manually analyzing the code. Once that's done I measure it with a debugger to make sure I didn't make a mistake. In FCEUX you can put a breakpoint at the start and end of the thing you want to time, and whenever a breakpoint is hit it will display the cycles since the last break in the debugger. You can also just put a breakpoint at the end of your PPU update code and see what scanline/pixel you're on when you hit it. (Nintendulator's debugger has similar features.)

2. There is a hodgepodge collection of various useful and unuseful pieces of code on the wiki, and scattered throughout this forum if you want to try searching.

You might find some of the more useful code on the wiki by starting at: http://wiki.nesdev.com/w/index.php/Programming_guide
Re: Algorithms, Assemblers, and IDEs
by on (#179949)
1:

I have a "VideoUpdatesBudget" variable that specifies how much time/space is still available for video updates. This is measured in units of "8 cycles per byte", because that's the general cost of transferring 1 byte. This variable is reset to 212 (212 bytes or 1696 cycles) at the start of every frame.

Every time the engine requests an update, the budget variable is adjusted according to the cost of each type of update, which is read from a table. The cost is either the number of cycles the update takes divided by 8 and rounded up, or the number of bytes it takes on the update buffer, whichever is larger. Once there's no budget left, all requests are denied.