Finally, some real programming!
Let’s do the simplest possible thing, to make sure that ca65 is working and we can get something to assemble correctly. We are going to turn the screen red.
.p816 .smart .include "defines.asm" .include "macros.asm" .include "init.asm" .segment "CODE" ;enters here in forced blank main: .a16 ;just a reminder of the setting from init code .i16 phk plb A8 stz CGADD ; set color address to 0 lda #$1f ;palette low byte gggrrrrr sta CGDATA; 1f = all the red bits lda #$00 ;palette high byte -bbbbbgg sta CGDATA; store zero for high byte ;turn the screen on (end forced blank) lda #$0f sta INIDISP ;$2100 InfiniteLoop: jmp InfiniteLoop .include "header.asm"
Notice that every asm file is included into the main file. That is to keep our compile.bat as simple and error proof as possible. I have put the SNES_01 folder inside my cc65 folder, and so the path to the bin folder is ..\bin\
Let’s go over every line.
.p816 – puts the assembler in 65816 mode
.smart – tell the assembler to automatically adjust register size depending on REP / REP changes (handled through macros like A8, AXY16, etc)
.include – all of our constants, macros, init code, and header file.
.segment “CODE” – where will our main code end up, in the CODE segment
main: – our label, where the init code jumps to at startup
.a16 / .i16 – this is what the register size was when it left init. These are assembler directives to set A and XY assembly to 16 bit size.
phk / plb – not that important here, but sets the Data Bank Register to the same as the Program Bank (which is currently $80, a mirror of $00, and necessary for fastROM).
A8 – a macro to put the A register in 8 bit mode, I know it’s confusing since I just told the assembler to do A16 a second ago. If you like, you can delete the .a16 line since we change it right away, but I like to leave directives just to remind myself what the settings were just before we got here.
stz CGADD ;$2121 – set the palette address register to zero
lda #$1f – load A register with the value $1f – the low byte of the color $001f = red.
sta CGDATA ;$2122 – send the low byte to the palette (CGRAM)
lda #$00 – load A register with the value $00 – the upper byte of the color.
sta CGDATA ;$2122 – send the high byte to the palette
lda #$0f – full brightness, no forced blank
sta INIDISP ;$2100 – effectively turns the screen ON
$2100 hardware register bits… x- – -bbbb
x = forced blank if set (turns off screen rendering)… $80
b = screen brightness, from 0 = black to $0f = full brightness
jmp InfiniteLoop – will jump repeatedly to this line
Now, we did NOT activate anything on the “main screen”, such as layers 1,2,3, or 4, or sprites (objects). With nothing on main, only the background color will show, which is the 0th palette entry.
Each color is 15 bits, BGR (the upper bit should be 0). Try changing the color and re-assembling. If you run it in MESEN-S, remember to reload from file/open and not click on the picture of the file (which only reloads the savestate, rather than reloading from file).
black = $0000
red = $001f
green = $03e0
blue = $7c00
white = $7fff
Here’s what it looks like. It’s not much, but we need to start somewhere.
And, if you look at the palette viewer, you can see our color at index 0.
Before we go, I just want to briefly mention the other files here.
Init.asm is the RESET code (and a few other bits). It zeroes all the registers and RAM and gets us to square one, before jumping long to main. Don’t feel like you need to understand every line in this file. Focus on the main code for now.
Macros.asm is a few macro definitions, like A8, AXY16, etc.
Defines.asm is a bunch of constants. I really hate the official names of each register, and I made my own list of names that I can read more easily. If you want to see the official list (and read about the hardware registers) go here…
And, lastly, the compiled ROM is the SNES_01.sfc file. This is what you should open in an emulator. I recommend the MESEN-S emulator. The usual file extension for SNES files are .sfc or .smc. SFC for Super Famicom and SMC for Super Magicom (a cartridge dumper / copier from the old days).
Now, I had written a library of code (EasySNES), but I did not use most of it here. I was discussing the matter with some friends, and I feel that SNESdev could be taught better with simpler examples, and the library will just obfuscate what is really going on.
(SNESdev SNES SFC Super Nintendo Super Famicom programming tutorial)
My apologies, since this first tutorial is essentially the same as this one…
I didn’t copy it. We just both coincidentally arrived at the same first step. Oh well. The next steps will be different.