Have you ever wanted to code for the NES, but you didn't know how? Do you want 8-bit programming knowledge, but instead you're stuck with 16 bits of fear? (That's trying to be a joke.) Want to write the next Super Mario Bros.? Your journey begins here! This is my version of "Hello, World" for the NES, and I offer the code to you as an opportunity to begin learning to program for the NES/ASM 6502.
ASM 6502 is the assembly language used to program on the NES. If you've never programmed in an assembly language before, it can be a bit difficult at first, but with a bit of time and patience you can learn it, just like any other language.I've added a lot of comments to the code (most of the code is commented), so this should help you as far as understanding what's going on with each line of the program, but you will of course need to learn the ASM6502 language. To do that, you'll need some kind of reference. My recommendation at this point would be to use ChibiAkumas' great "cheat sheet", which is downloadable for free here: https://www.chibiakumas.com/book/CheatSheetCollection.pdf (I also recommend his book on learning ASM6502, and suggest you use it to learn the commands while you're away from the computer... you can find it here: https://www.amazon.ca/gp/product/B0BKMS6752 It's a great book for study time away from the computer, too!)
If you're looking to compile the code, you'll need to use the VASM compiler. You can get it here: http://www.compilers.de/vasm.html . It's a great compiler that can be used for a variety of systems, and it was made by Dr. Volker Barthelmann. Check it out! To compile simply use:vasm6502_oldstyle.exe DIR/helloworld.asm -chklabels -nocase -Fbin -o "DIR2/helloworld.nes"
In C++, it's 4 or 5 lines.
In ASM 6502?
Well... including spaces and comments we're clocking in at around 250 lines of code. Yikes! But fear not! While there is much to learn, if you take it step by step, you'll see it's not so bad. I've taken great pains to comment just about every line of code in this sample program, so you should at least have an easier time figuring it out. Let me give you some other tips, too, to make learning ASM6502 programming easier. The general layout for NES code is as follows:
- Header
- Labels (e.g. someLabel equ $01)
- NMI, IrqHandler, Program Reset/Initialization
- Game Loop
- Data/Lookup Tables/Functions
- Footer
- Tile Data
Let's go over these sections in more detail.
These are all labeled pretty clearly in the program, and all are necessary for a functioning NES cartridge. The Header (the part with "db "NES",$1A", etc.) is included in every NES program, and while changes can be made to some parts of the header, in the beginning I would recommend leaving it as is. As with all parts of the code, you can learn the specifics of what each line does, and try modifying them later as you see fit. In this particular program there are no labels... but if there were, they'd look something like this: playerHealth equ $27 ; playerHealth can be used instead of writing $27
- 1) #playerHealth gives you the number $27, but playerHealth gives you the value stored at $27. I often mix the two up... in fact, I'm tempted to go double-check right now, just to make sure I got it right... yep, we're good. (*Phew*)
The IrqHandler section is what happens during a system hardware interrupt, but we've disabled all of that (except for the screen refresh, AKA the NMI - the Non-Maskable Interrupt).
Again, these are all essential parts of the program, and you must include them.
This is an interesting part of the game's program. The game loop is necessary because, if there were no loop, the game code would run once and be done! (Which probably wouldn't make for a very fun game, in most cases.) So the question is, what code do we find here? In the case of this particular program, there's basically nothing but the loop itself. Why, you might ask? It's a simple enough program that only needs the loop to keep the game from ending/crashing.Some game developers would apparently put most of their code in the NMI (I'm told Konami is one such company), whereas others would make use of the game loop to put their code. This is all a bit above the scope of this tutorial, but if you're interested in reading more, you can learn more about it here: https://www.nesdev.org/wiki/NMI_thread, and https://www.nesdev.org/wiki/The_frame_and_NMIs
This is where we store data for things like the order of background tiles, or the placement of sprites (NOTE: not the tile "blueprints" i.e. the design for the tiles, that comes later!), or any useful information that we might to look up (hence the name "look up table" or LAT). You'll see here I've put my data for the sprites for hello world, here. In fact, each group of 4 pairs of hexidecimal numbers gives (in this order): the y-coordinate, the tile-number, special attributes (none in this case), and the x-coordinates of each tile. I think I've marked it clearly enough in the program, but this can be a fun part of the program to modify if you're just looking to get your feet wet, so to speak. Modify the first number in any row, and you'll find the letters are in a different row. Modify the last value, and their x-coordinate will change. The 2nd value modifies which tile it is (so you could spell something entirely different), and the third attribute... well, it's a little more complicated, so perhaps we'll leave it for now (or if you're curious, you can read about it on nesdev's wiki here: https://www.nesdev.org/wiki/PPU_OAMAs for functions, well, technically you can include them anywhere - the order of your code mostly doesn't matter as long as the control flow of your program works. If you've got the appropriate jmps, jsrs and whatnot, you should be fine (if I'm being honest, looking over my code I can see some spots where maybe a little more organization might improve its readability!)
This is another one of those sections where the code is simply necessary, and you probably shouldn't change it. Here we choose our names for:- our NMI (non-maskable interrupt AKA the screen refresh),
- our reset (the code that runs on loading/resetting the game),
- and our IRQ (other interrupts)
- A zero in both grids means it's colour 0 (background)
- A 1 in bitplane 1 (and zero in bitplane2) gives us colour 1
- A 1 in bitplane 2 gives us colour 2
- A 1 in both bitplanes gives us colour 3
An excellent (but not too difficult) exercise would be to change the tiles from "Hello World!" to something different, like "Hello [your name here]!" Can you see how you might do this?
Congratulations! If you've read this far, I'm hoping it's because you've succeeded in compiling this code, maybe even editing it to suit your own purposes. If there's still any confusion left, that's completely normal! I learn new things about ASM 6502 everyday, and with time your confidence with the language will grow as mine has. There's always more to learn!
If you feel you've really absorbed what you can from this program, take a look at my other sample programs. Each one teaches you something new about the NES, and then we put it all together to make a game called Birthday Blast! Here are the links:
Feel free to copy this code, modify it, and use it for either personal or commercial purposes. If you manage to sell a cartridge copy of "Hello, World!", let me know! I'd love to see it ;)