NES Hello World ROM template_project
authorRhett Aultman <roadriverrail@gmail.com>
Thu, 13 Sep 2018 16:30:43 +0000 (12:30 -0400)
committerRhett Aultman <roadriverrail@gmail.com>
Thu, 13 Sep 2018 16:30:43 +0000 (12:30 -0400)
This is a commit showing all the basic boilerplate needed to compile
and link an rom for NES emulators.  This requires cc65 to compile.  The
ROM will produce a buzzing square wave on the audio synthesizer and then
loop forever, but it's a great "first ROM" and contains the
documentation you really need to understand what's going on.

.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
README.md
src/helloworld.asm [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..cd42ee3
--- /dev/null
@@ -0,0 +1,2 @@
+bin/
+obj/
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..cba867c
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,27 @@
+SRCDIR = src
+OBJDIR = obj
+BINDIR = bin
+TARGET = helloworld.nes
+
+SOURCES := $(wildcard $(SRCDIR)/*.asm)
+OBJECTS := $(SOURCES:$(SRCDIR)/%.asm=$(OBJDIR)/%.o)
+rm      = rm -f
+
+.PHONY: all
+all: directories $(BINDIR)/$(TARGET)
+
+.PHONY: directories
+directories:
+       @mkdir -p $(OBJDIR)
+       @mkdir -p $(BINDIR)
+
+$(BINDIR)/$(TARGET): $(OBJECTS)
+       cl65 -t nes -o $@ $(OBJECTS)
+
+$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.asm
+       ca65 -o $@ $<
+
+.PHONY: clean
+clean:
+       @$(rm) $(BINDIR)/$(TARGET)
+       @$(rm) $(OBJECTS)
index bdf3ea88159256c3d74986fecd7eccc36211d7f1..b682bb30fe3ad3e30d7de815eded1f83ea7d2d7e 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,2 +1,22 @@
-# nes_coding
-Writing code for the NES
+# NES coding exploration
+
+This is a project covering my exploration of coding 6502 assembly for the NES.
+
+The goal isn't to produce a game, per se, but to hopefully learn to work with
+the NES architecture, tools for producing ROMS, etc.  These little "lab
+sessions" should be accessible to anyone with some modest background in systems
+programming.
+
+These are developed on KDE Neon (Linux), and the Makefile may not work for
+Windows.
+
+You will need a copy of [cc65](https://github.com/cc65/cc65) built and
+installed.  My preferred emulator/debugger is
+[mednafen](https://mednafen.github.io/releases/), which on Ubuntu systems can be
+installed with a simple `sudo apt-get install mednafen`.
+
+To build and run:
+```
+make
+mednafen bin/<name_of_rom>.nes
+```
diff --git a/src/helloworld.asm b/src/helloworld.asm
new file mode 100644 (file)
index 0000000..3ddbea6
--- /dev/null
@@ -0,0 +1,77 @@
+; Hello World for the NES
+;
+; This initial program is purely to test out the assembling and linking
+; features of cc65 and to prove out a build process that will make an
+; iNES-format ROM suitable for use on most emulators.  There is no console
+; output for the NES and no default set of characters for text output, so
+; the traditional "Hello World" output has been replaced with generating a
+; simple square wave on the audio synthesizer.  If your copy of mednafen is
+; configured correctly for audio and everything builds correctly, you should
+; hear a buzzing noise from the speakers and see a blank window/screen.
+;
+; The code to generate the square wave came from some code recommended by the
+; NESDev Wiki at:
+; https://wiki.nesdev.com/w/index.php/Programming_Basics#.22Hello.2C_world.21.22_program
+;
+; What was seriously lacking from this wiki, however, was information on how
+; cc65 links together a complete ROM using the "-t nes" flag.  Hopefully, this
+; code will help spare a future hobbyist some time in understanding how everything
+; goes together.
+
+; for reference on the linker config, I suggest you pull down the cc65 source and
+; locate the "cfg/nes.cfg" file, which provides the layout of the ROM
+
+
+; Mandatory iNES header.  Without this, the emulator will likely not load your ROM.
+; cc65 declares its location and size in the nes.cfg file
+.segment "HEADER"
+
+.byte "NES", $1A ; "NES" magic value
+.byte 2          ; number of 16KB code pages (we don't need 2, but nes.cfg declares 2)
+.byte 1          ; number of 8KB "char" data pages
+.byte $00        ; "mapper" and bank-switching type (0 for "none")
+.byte $00        ; background mirroring flats
+                 ;
+                 ; Note the header is 16 bytes but the nes.cfg will zero-pad for us.
+
+; Like with "HEADER", "STARTUP" is declared in the nes.cfg file.  Your code must
+; fit within this 32 KB segment (for now).  All your code effectively goes here.
+; I will not go into length on 6502 assembly, but I will note this loads a buzzy
+; square wave into the audio synthesizer and then loops forever.  You must supply
+; the label for your startup code in the "VECTORS" segment below
+
+.segment "STARTUP"
+
+reset:
+  lda #$01     ; square 1
+  sta $4015
+  lda #$08     ; period low
+  sta $4002
+  lda #$02     ; period high
+  sta $4003
+  lda #$bf     ; volume
+  sta $4000
+forever:
+  jmp reset
+
+nmi:
+  rti ; Return from the NMI (NTSC refresh interrupt)
+
+; "VECTORS" is another mandatory section.  It must contain a table for three
+; things, in order.  The first is for the non-maskable interrupt (NMI), which
+; is the NTSC video signal vertical sync (among other things).  This interrupt
+; triggers on the end of every pass of an NTSC television and is crucial for
+; timing game logic.  The second is the entry point of your program, triggered
+; off the "reset" interrupt which is delivered at power on and at any press of
+; the NES reset button.  The third handles assorted interrupt requests (IRQs)
+; from the system and is not used in this program.
+
+.segment "VECTORS"
+.word nmi
+.word reset
+.word 0
+
+; "CHARS" is a reserved section for data.  Our program has no data, so this
+; is only here to help the linker finish laying out the ROM.
+
+.segment "CHARS"