Starting my NESdev journey

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
User avatar
Individualised
Posts: 310
Joined: Mon Sep 05, 2022 6:46 am

Starting my NESdev journey

Post by Individualised »

Now that I have a computer that is suitable for the task, I feel like it's finally time for me to jump into NES homebrew development, after reading up on the NES hardware for so long. I'd like to try and start in the "best" possible way though, so I created this thread to ask what assemblers/other tools to use and what tutorial I should be following, and maybe ask for help further along the line. My plan is to first work my way through a tutorial such as Nerdy Nights so I can get the hang of 6502 assembly, then write some basic test programs independently, then move on to making some simple NROM games and after that maybe attempting some mapper 1 or MMC3 stuff.

One of the main issues I have with beginner's tutorials though, and I believe that Nerdy Nights is like this too having skimmed through it a few times before, is that they assume the user has no prior knowledge of the hardware, or even programming or computer science concepts in general (for example Nerdy Nights begins by explaining number systems and that computers work in binary...). I'm in a bit of a weird spot, where I know all the concepts/theory, I know how the NES hardware functions, I understand how a CPU executes machine code etc, I'm just rusty on putting into practice - actually writing assembly code. This isn't something I've just experienced with NES or retro homebrew stuff either, I remember when I was first learning to program in Java and it was a similar situation for a lot of tutorials I was trying to follow then too, where I quickly lost interest due to them repeatedly explaining basic programming concepts that I already knew. Additionally I know that Nerdy Nights is based around some tools that are considered by some to now be outdated (i.e. NESASM, also keep in mind that I run Ubuntu so while I can run Windows tools in Wine I'd like to keep this as native to my OS as possible). So, I was wondering if there was a "getting started" NES development tutorial that's targeted to users with more advanced knowledge, or should I just stick with Nerdy Nights since it usually seems to be considered the best for beginners? Or should I just look up general 6502 assembly tutorials, since that's really what I mainly need to learn?

Much thanks in advance and looking forward for any response.
Fiskbit
Posts: 891
Joined: Sat Nov 18, 2017 9:15 pm

Re: Starting my NESdev journey

Post by Fiskbit »

It sounds like you don't really need a tutorial, per se, but rather just some starting materials and direction. I haven't gone through any of the tutorials myself, but in addition to often locking you into tools that aren't generally well-liked these days, they often don't have the best program design and can teach bad habits.

For assemblers, ca65 seems to be the most well-liked, stable, mature, and featureful. Its main drawback is that it's not as beginner-friendly as other assemblers because it has a linking phase, thus requiring a linker config file. Tepples has a template available here that can get you started with ca65 and linking: https://github.com/pinobatch/nrom-template. Because ca65 links, it can be harder to know exactly where your code is compared to an assembler like ASM6, though this is rarely a significant issue. ca65's anonymous labels are also very lacking compared to other 6502 assemblers; it uses what I've seen referred to as Ophis-style labels, where your jump target is specified as being some number of anonymous labels forward or backward, but this is extremely fragile because adding or removing anonymous labels can break jumps. As such, it's only suitable for 1 or 2 anonymous labels in very close proximity. However, ca65 has excellent support for scoping (.proc directive), so it's easy to use local named labels without polluting the global namespace.

I generally recommend as a starter project that people do something small and simple like Pong. This is enough of a game to teach you the basics of most of the concepts the system requires. To make Pong, you have to handle system init, writing palettes, writing nametables and attributes tables, NMIs, controller input, and an object system with drawing, movement, and collision. You can do simple audio, too, though most people use some kind of audio engine library such that it's mostly a matter of making sound effects and triggering them at the right time. Notably absent from this game is scrolling, but a lot of homebrew doesn't scroll, anyway.

Below is some skeleton code to get you started with good practices for making a game. This is roughly what the NMI handler and frame loop look like in the games I've made.

Code: Select all

.proc HandleNmi
  ; Save registers.
  PHA
  TXA
  PHA
  TYA
  PHA

  ; If this is a lag frame, do not touch the PPU. We still want to handle audio, though.
  LDA frame_ready
  BNE PpuDone

  ; Write the contents of the VRAM transfer buffer to the PPU.
  BIT PPU_ADDRESS
  JSR HandlePpuWrites

  ; Set rendering flags. Rendering should generally be toggled in vblank.
  LDA ppu_mask_next
  STA PPU_MASK
  STA ppu_mask_value

  ; Set the scroll and other flags. Scroll must be set after VRAM writes are complete.
  LDA ppu_control_next
  STA PPU_CONTROL
  STA ppu_control_value

  LDA scroll_x
  STA PPU_SCROLL
  LDY scroll_y
  STY PPU_SCROLL

  ; We do OAM DMA last in vblank because doing it too late is the least disruptive of our possible PPU actions.
  LDA #$00
  STA OAM_ADDRESS
  LDA #>oam_buffer
  STA OAM_DMA

  ; Mark that we've handled the start of this frame already.
  LDA #$01
  STA frame_ready

 PpuDone:

  ; We do this every NMI, even if it's a lag frame, because lagging audio can be more disruptive than lagging gameplay.
  JSR HandleAudio

  ; Restore registers.
  PLA
  TAY
  PLA
  TAX
  PLA
  RTI
.endproc

.proc HandleFrame
  ; Wait for the NMI to run.
 :
  LDA frame_ready
  BEQ :-

  JSR ReadJoypads

HandleMode:
  ; Run the handler for the current game mode using a jump table.
  LDA current_mode
  ASL
  TAX
  LDA dModeHandlers,X
  STA indirect_jump_pointer
  LDA dModeHandlers+1,X
  STA indirect_jump_pointer+1
  JSR DoIndirectJump

  ; Commit any changes to the game mode and mode state.
  LDA next_mode
  STA current_mode
  LDA next_state
  STA current_state

  ; Indicate that the frame is done.
  LDA #$00
  STA frame_ready

  JMP HandleFrame
.endproc
Most of the concepts here have pages on the wiki. These pages include example code that should work as-is:

Init code
Jump tables
Reading controllers

For a game as simple as Pong, you don't necessary need a HandlePpuWrites function, but it's an extremely common concept across most games. The idea here is that you have some kind of transfer buffer, which at its simplest, is a PPU address, number of bytes, and list of bytes of that length. Then you either have a terminator (such as a negative number; PPU addresses are big endian and always have the highest bit clear) or another address/length/data structure, repeating until a terminator is hit. Often times these formats have flags indicating things like write direction (whether the data is written rightward (add 1) or downward (add 32)) or compression format (run-length encoding is common). You can also have the location of the buffer vary, so a pointer can indicate it's in RAM for a mutable buffer or in ROM for a fixed buffer, the latter useful for things like a title screen.

That's probably enough info to start with. Please ask questions as you have them. I'm sure others will chime in with other suggestions!
User avatar
Individualised
Posts: 310
Joined: Mon Sep 05, 2022 6:46 am

Re: Starting my NESdev journey

Post by Individualised »

Thank you for the thorough reply, this is very helpful info! I've taken your suggestions into consideration. I agree that it may just be best for me to jump straight in using my current knowledge and learn as I go.

I'll be sure to ask more questions!
dsilberg
Posts: 3
Joined: Sat Aug 06, 2022 7:07 am

Re: Starting my NESdev journey

Post by dsilberg »

Is there any kind of intro/tutorial on ca65's syntax/features/language? I see a lot of references to features of the assembler but I don't really know how to leverage them. For example you mentioned scope in .proc, where can I learn more?
Catyak
Posts: 54
Joined: Mon Apr 25, 2022 4:33 pm

Re: Starting my NESdev journey

Post by Catyak »

dsilberg wrote: Tue Dec 27, 2022 7:58 am Is there any kind of intro/tutorial on ca65's syntax/features/language? I see a lot of references to features of the assembler but I don't really know how to leverage them. For example you mentioned scope in .proc, where can I learn more?
Have you looked at the user guide already?
Pokun
Posts: 2681
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: Starting my NESdev journey

Post by Pokun »

There are also examples using it like Rainwarrior's template which I think is a good start for learning how to use ca65.



Answering OP, I agree with Fiskbit that you should start making Pong after having learned the bare basics such as drawing a background displaying a sprite and moving it with the controller. Pong doesn't require a metatile system and only a very simple metasprite system, or you can even get away with hardcoding sprites since there are only 3 entities (2 paddles and 1 ball).

Here is another wiki page I highly recommend you to read after making Pong:
The frame and NMIs

Although Nerdy Nights starts off very basic, it does teach you 6502 in a very introductory way which is excellent and I think is its forte. If you already know 6502 well you can skim it or just check it for some hints on how to make Pong if you are stuck, but otherwise it's still a very good tutorial for learning all the basics of 6502 that you will need to make NES games. I knew hexadecimal and many other things when I started following it, those are things you just may want to skim through if you know them already, all tutorials may have things like this that are too easy for you, so you need some patience.
One thing it does differently is that it puts all code (except the init code) in the NMI (which is what some commercial games like Super Mario Bros also actually does) instead of just having PPU updates there and keeping game logic outside of it like most homebrewers prefer. But by looking at the examples given to you, I think you may figure it out.

The more advanced Nerdy Nights tutorials may also teach you some things. Especially the sound tutorial by Metalslime, it's probably the best Nerdy Nights tutorial of them all. Definitely read it to learn how to use the APU, and it also teaches how you can make a simple system for buffering PPU writes (referring to the "The frame and NMIs" article), though without RLE nor does it work with ROM data directly but it's good enough for most programs. It does teach you how to separate logic and graphic updates using the NMI too.
It's not a too beginner-friendly tutorial though, it teaches you how to build a fully functional and actually pretty advanced sound engine with variable tempo and custom envelopes. It's the only one of its kind that I've seen.
User avatar
Individualised
Posts: 310
Joined: Mon Sep 05, 2022 6:46 am

Re: Starting my NESdev journey

Post by Individualised »

6502 assembly is pretty much the main thing I need to learn. Like I said in the OP, I know the theory, I think I have a decent understanding of the workings of the NES hardware and it's features/quirks, and how I'd theoretically interface with it; but I can't yet put it into practice. I suppose that I could start independently and use Nerdy Nights as a reference. Thanks for the reply!
User avatar
Individualised
Posts: 310
Joined: Mon Sep 05, 2022 6:46 am

Re: Starting my NESdev journey

Post by Individualised »

Alright, so a few hours ago I downloaded tepples's example game as a test, and set up a ca65 workspace and managed to assemble it, which was a surprisingly intuitive thing to do. What I think I'm going to do is use Nerdy Nights as a reference for understanding 6502 assembly, and try to create a Pong game similar to as it teaches, but I won't follow the tutorial itself, if that makes sense.

First though, I'd like to know how to be able to view the source assembly in Mesen's debugger, rather than disassembled code. I assume that there is some sort of assembler option that I need to use that will create a debug file that I can load into Mesen, correct?
Pokun
Posts: 2681
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: Starting my NESdev journey

Post by Pokun »

I see, that is kinda what I do too when following a tutorial and I only need to get some pointers from it. You may want to try and get the code from the Nerdy Nights lessons working in ca65 as a challenge and to get some real 6502 practice.

I'm not sure if Mesen can read your source code. There are ways to get it to use your label names in its disassembly though, but I'm not sure how to do that with ca65.
User avatar
Individualised
Posts: 310
Joined: Mon Sep 05, 2022 6:46 am

Re: Starting my NESdev journey

Post by Individualised »

Alright then. Meanwhile, early this morning (around 12 hours ago in my timezone), I had a little fun with the example program and did a little exercise:
Image
This wasn't just a CHR and palette swap - I'm using the unmodified SMB1 background CHR here, and since the tiles are generated programmatically, I had to rewrite the code that draws the columns and the floor (and of course, the floor is a different pattern too.). This helped me to understand both assembly program flow as well as how certain instructions exactly work better.

Tomorrow, I'll try beginning from a blank canvas and try to recreate the Nerdy Nights pong game in ca65 but using the basic init code posted above.
Fiskbit
Posts: 891
Joined: Sat Nov 18, 2017 9:15 pm

Re: Starting my NESdev journey

Post by Fiskbit »

For symbols, I pass -g to ca65 and --dbgfile [filename].dbg to ld65. I think Mesen will load the .dbg file automatically if it's beside a same-named .nes file.
User avatar
Individualised
Posts: 310
Joined: Mon Sep 05, 2022 6:46 am

Re: Starting my NESdev journey

Post by Individualised »

That's exactly what I was looking for! Even shows comments, not just label names. Thanks!
Post Reply