65816 Assembly programming for the SNES and Super Famicom

The Super Nintendo (AKA Super Famicom)  was the sucessor to the NES... relatively late to the 16 bit game, the SNES made the unusual choice to not use the 68000 CPU for its processor, favoring the slower and less efficient 65186... this is roumoured to be because during development backwards compatibility with the NES was planned...

The 65186 is a true 16 bit CPU, but it has a 6502 compatibility mode, in which it works exactly like a 6502, and we can perform basic SNES programming without even using a 16 bit command!
Cpu 3.58 mhz 65816 
Ram 128k
Vram 64k
Tiles 1024
Sprites 128 onscreen (32 per line)
Resolution 512x448
Colors 256 (16 per tile) from 32768 
Sound chip 64k DSP 8 channel  SPC700
The UK SNES PSU outputs 9V AC the Japanese Super Famicom PSU outputs 10V DC - CENTER NEGATIVE BE CAREFUL! adaptors that output AC are very rare and will kill most systems - and Center negative was common for 80's Japanese systems, but is very rare these days - YOU HAVE BEEN WARNED!


ChibiAkumas Tutorials

   
Lesson P7 - Bitmap Functions on the SNES / Super Famicom

Lesson P15 - Joystick Reading on the NES / Famicom and SNES

Lesson P22 - Palette Definitions on the SNES / Super Famicom

Lesson P27 - Sound on the SNES / Super Famicom: the SPC700




Memory Map

The 65816 has a 16 bit address bus, it generally works with a 16 bit address, and a 8 bit Data Bank register (DB)

The ZeroPage and Stack pointer are relocatable, but default to the 6502 normal of $0000-$01FF

Our minimal 32k cartridge will appear in rom from $8000, and execution will start there, the CPU will default in 8 bit mode.
Bank 16 bit address Purpose
$00-$3F $0000-$1FFF RAM

$2000-$5FFF Hardware Regs

$6000-$7FFF Expand (???)

$8000-$FFFF Cartridge Rom
$70 $0000-$7FFF Battery Backed Up Ram
$7E $0000-$1FFF Scratchpad RAM (same as bank $00 to $3F)

$2000-$FFFF RAM
$7F $0000-$FFFF RAM

VRAM

VRAM addresses are reconfigurable, Here's a sample map which we'll be working around in these tutorials ... Note the addresses are in WORDS (2 bytes in each address)... so the 64k memory is accessed by addresses $0000-$7FFF

 Address  Use
$0000  BG1 Tilemap
$1000  Tile Patterns
$4000  Sprite Patterns
$7FFF  Last byte of ram 

Cartridge Header
Address Bytes Category Purpose Example
$FFC0 21 Rom Cartridge title (Space Padded) Test Rom9012345678901
$FFD6 1 Rom ROM/RAM information on cart. $00
$FFD7 1 Rom ROM size. $01
$FFD8 1 Rom RAM size. $00
$FFD9 1 Rom Developer ID code. $00
$FFDB 1 Rom Version number. $00
$FFDC 2 Rom Checksum complement. $????
$FFDE 2 Rom Checksum. $????
$FFE0 2 65816 Mode
$0000
$FFE2 2 65817 Mode
$0000
$FFE4 2 65818 Mode COP Vector $0000
$FFE6 2 65819 Mode Brk Vector $0000
$FFE8 2 65820 Mode Abort Vector (Unused) $0000
$FFEA 2 65821 Mode NMI Vector (V-blank) $0000
$FFEC 2 65822 Mode Reset Vector (Unused) $0000
$FFEE 2 65823 Mode IRQ Vector (H/V/External) $0000
$FFF0 2 6502 Mode
$0000
$FFF2 2 6503 Mode
$0000
$FFF4 2 6504 Mode COP Vector $0000
$FFF6 2 6505 Mode BRK Vector (unused) $0000
$FFF8 2 6506 Mode Abort Vector (Unused) $0000
$FFFA 2 6507 Mode NMI Vector (V-blank) $0000
$FFFC 2 6508 Mode )Reset Vector (6502 Mode) $8000
$FFFE 2 6509 Mode IRQ/BRK Vector $0000

Sound on the SNES via the SPC700
To make sound on the SNES we have to use it:s SPC700 processor! what's the SPC700? well it's an 8 bit dedicated sound CPU with 64k of isolated memory - meaning that it can't be directly accessed from the main CPU!
The SPC700 is a great sound processor, used by the Super Nintendo and many other systems like... er.. the super nintendo!
Ok, so nothing else uses it, and it's a total pain!  while it's sound ability is good, its a real hassle to program... it uses it's own special instruction set, and its bytecode matches no other CPU, and data has to be transferred to it using a special procedure because we can't access it's memory directly.

The CPU is 8 bit and Little endian, so $1234 is stored in ram as $34,$12... it's registers are the same as the 6502, but it has some 16 bit commands that use YA as a 16-bit pair like the Z80

 it has a ZeroPage, but the ZeroPage is referred to as the DirectPage, as it can be at $00xx or $01xx... $01xx is also used as the Stack

Most data transfer commands are done with MOVe commands (like the 68000), but like the z80, the destination is on the left... for example:
mov a, #$00     ;Set A to $00

I'm not planning to go into greater detail than I need on this CPU, so please see the tutorials below:
Best SP700 reference
Also a good tutorial

Sound samples must also be held in SPC700 ram...

Pointers to Sound samples are stored in a single block..  this block must be byte alined, and has 256 sound definitions - each of which contains 2 pointers... one for the start of the sample, and one for the loop

For example, take the example definition, this will be loaded into SPC700 ram at $300... we would tell the sound chip to use $03 as the memory position using the "DIR" sound register $5D

The sound samples themselves are made up of 9 byte chunks, the first byte is a header, and the other 16 nibbles are the sound data... the final sample in the sound should have the End bit set in the header, and the Loop bit if you wish
    align 8
SFXBank:                                    ;We're going to load this into $0300
    dw SFXBank_Sound1-SFXBank+$300            ;Sample 0 main
    dw SFXBank_Sound1-SFXBank+$300            ;Sample 0 Loop
    align 4
SFXBank_Sound1:
    ;     SSSSFFLE S= bitshift (0-12) FF=Filter L=Loop E=End
    db  %11000111,$FF,$F0,$F0,$F0,$F0,$F0,$F0,$F0
    ;              01  23  45  67  89  AB  CD  EF
   

The SPC700 Memory Map

Start 
End Purpose
0000 00EF 
Zero Page / Direct Page
00F0 00F0 Unused
00F1 00F1 Control Port (Timers & reset)
00F2 00F2 Sound Register Select
00F3 00F3 Sound Register Value
00F4 00F4 Link to 65816 address $2140
00F5 00F5 Link to 65816 address $2141
00F6 00F6 Link to 65816 address $2142
00F7 00F7 Link to 65816 address $2143
0100 01FF Stack
0200 FFBF RAM
FFC0 FFFF ROM

The SPC700 Registers

Address Register Description Bits Meaning
c0 VOL (L) Left Volume -VVVVVVV Volume
c1 VOL (R) Right Volume -VVVVVVV Volume
c2 P (L) Pitch L PPPPPPPP Pitch
c3 P (H) Pitch H --PPPPPP Pitch
c4 SRCN Source number (references the source directory) SSSSSSSS Source
c5 ADSR (1) If bit7 is set, ADSR is enabled. If cleared GAIN is used. EDDDAAAA Enable, Dr, Ar
c6 ADSR (2) These two registers control the ADSR envelope. LLLRRRRR sL,sR
c7 GAIN This register provides function for software envelopes. GGGGGGGG G=Envelope bits
c8 -ENVX (auto updated) Readable current Envelope Value 0VVVVVVV Value
c9 -OUTX (auto updated) Readable current Waveform Value SVVVVVVV Signed Value
0C MVOL (L) Main Volume Left -VVVVVVV Volume
1C MVOL (R) Main Volume Right -VVVVVVV Volume
2C EVOL (L) Echo Volume Left -VVVVVVV Volume
3C EVOL (R) Echo Volume Right -VVVVVVV Volume
4C KON Key On CCCCCCCC Channel
5C KOF Key Off CCCCCCCC Channel
6C FLG DSP Flags. (used for MUTE,ECHO,RESET,NOISE CLOCK) RME----- Reset (0=off) Mute (0=off) Echo (1=0ff)
7C -ENDX (auto updated) read to see if channel done CCCCCCCC Channel
0D EFB Echo Feedback SFFFFFFF Signed Feedback
2D PMON Pitch modulation CCCCCCC- Channel (1-7)
3D NON Noise enable CCCCCCCC Channel
4D EON Echo enable CCCCCCCC Channel
5D DIR Offset of source directory (DIR*100h = memory offset) OOOOOOOO Offset $oo00
6D ESA Echo buffer start offset (ESA*100h = memory offset) OOOOOOOO Offset $oo00
7D EDL Echo delay, 4-bits, higher values require more memory. ----EEEE Echo delay
fF COEF 8-tap FIR Filter coefficients SCCCCCCC Signed Coeficcient
c = Channel 0-7 f = filter coefficient 0-7

SPC700 and VASM

Vasm doesn't support the SPC700, but we can simulate the commands with macros, for example, we can set an immediate value with the macro to the right         macro s_mov_a_ii,aval        ;Set A=immidiate value
            db $E8
            db \aval
        endm
If we want to do a relative jump, we can calculate the relative offset with Destination-(*+1) s_bne_r SoundCallPause-(*+1)
If we want to include our SPC700 code in our main rom, we'll need to adjust call addresses for the changing location, to do this we can use the formula [DestinationLabel]- [StartOfProgramInMainRom]+ [DestinationOfProgramInSPC700Ram] s_call_addr SoundCallResume-SoundProgram+SndPrgMemLoc   

Tile Definitions
Tile definitions use 4 bitplanes for 16 colors, and tile definitions are 8x8 - so 32 bytes ... Data is transfered in Words, and rather strangely we send bitplane 1+2 of lines, one at a time... then we do the same for bitplanes 3 and 4

Byte 1 Byte 2
First 16 bytes 00111100
01111111
01100011
01100011
01111111
01100011
01100011
00000000
00222200
02222222
02200022
02200022
02222222
02200022
02200022
00000000
Second 16 bytes 00333300
03333333
03300033
03300033
03333333
03300033
03300033
00000000
00444400
04444444
04400044
04400044
04444444
04400044
04400044
00000000

Tilemap Data
The Tilemap will typically start from address $0000, each entry contains two bytes

 F   E   D   C   B   A   9   8    
 7   6   5   4   3   2   1   0    

V H L P P P T T
T T T T T T T T
V=vflip H=hflip L=layer (in front of sprites) P=palette T=tile number

Palette Definitions 
Palettes are defined by something called 'CGRAM'
there are 256 palette entries...
Because we can only select 8 palettes for Tiles/Sprites, assuming our sprites and tiles are 16 colors the first 128 colors will be used by Tiles, and the second 128 will be used by Sprites

To define a palette entry we need to select a palette entry number by writing it's number as a byte to $2121

We have to write two bytes to $2122... we write them in REVERSE order, so the low byte is written first!

H byte (sent second)
L byte (sent first)
 F  E  D  C  B  A  9  8
 7  6  5  4  3  2  1  0
- B B B B B G G
G G G R R R R R


Sprite Definitions - Overview
Sprites use as special bank of 512 bytes of 'OAM' memory for their definitions... they also use standard VRAM for the pattern data.
In theory the Pattern data can be relocated... but in practice it's best to just assume it's at &2000 (address in 16 bit words)
Sprites can be various sizes - a 'default size' is set for all sprites... and certain selected sprites can be double size...
this is, however a bit tricky... lets say you have the default size as 8x8... and one double size 16,16 sprite
If we point this sprite 'double size' 16x16 sprite to pattern  'Tile 0',  the 4 8x8 chunks will be made up of tile numbers:
1 2
16 17

Lets look at this example of a 16x16 sprite in AkuSprite Editor... Akusprite editor is designed for 8x8 sprites, but we can export a 16x16 one in the following way

If we want to export this quickly, so we can use it as a single doublesize sprite, one option is to tick the 'FixedSize' tickbox, and set the size to 128,16

This will export the sprite correctly - of course there will be a lot of unused space in the exported file... so we would want to combine all our 16x16 together into a single image

Generally it would be easier to build up a 16x16 sprite from 4 8x8 sprites
Sprite Definitions - Ports Used
Address Name Purpose Bits Details
$2101 OBSEL OAM size (Sprite) SSSNNBBB S=size N=Bame addr B=Base addr
$2102 OAMADDL/L OAM address LLLLLLLL a=oam address L
$2102 OAMADDL/H OAM address R000000H R= priority Rotation / H=oam address MSB
$2104 OAMDATA OAM data ????????
$212C TM Main screen designation ---S4321 S=sprites 4-1=enable Bgx
$2138 OAMDATAREAD Read data from OAM


Sprite Definitions - OAM Data
Selecting a HL address is done by setting registers $2102 (L) and $2103 (H)
Each address below $0100 holds Two Bytes (The first table)...each address $0100 or above holds just one!... All data is written via the $2104 
Note, Sprites use Palettes from 128... so the color pallete used is the value in CCC +128
Sprite data should only be written to Vram during Vsync.
Address Byte 1 Byte 2 Meaning SprNum
$0001 XXXXXXXX YYYYYYYY X=Xpos (bits 0-7) Y=Ypos 0
$0002 YXPPPCCCT TTTTTTTT Y=yflip X=xflip P=priority compared to BG (C=palette +128) 0
$0003 XXXXXXXX YYYYYYYY X=Xpos (bits 0-7) Y=Ypos 1
$0004 YXPPPCCCT TTTTTTTT Y=yflip X=xflip P=priority compared to BG (C=palette +128) 1
$00FE XXXXXXXX YYYYYYYY X=Xpos (bits 0-7) Y=Ypos 127
$00FF YXPPPCCCT TTTTTTTT Y=yflip X=xflip P=priority compared to BG (C=palette +128) T= Tile Pattern number
127
$0100 SXSXSXSX (no 2nd byte) S=doubleSize sprite X=Xpos (bit 8) 0-3
$0101 SXSXSXSX (no 2nd byte) S=doubleSize sprite X=Xpos (bit 8) 4-6

$011F SXSXSXSX (no 2nd byte) S=doubleSize sprite X=Xpos (bit 8) 124-127


Ports
rw Address Name Purpose Bits Details
w $2100 INIDISP Screen display x000bbbb x=screen disable (1=disable) bbbb=brightness (15=max)
w $2101 OBSEL OAM size (Sprite) sssnnbbb sss^size nn=name addr bb=base addr
w 2 $2102 OAMADDL/H OAM address aaaaaaaa r000000m a=oam address r=priority m=addr MSB
wd $2104 OAMDATA OAM data ???????? ????????
w $2105 BGMODE Screen mode abcdefff abcd=tile sizes e=pri fff=mode def
w $2106 MOSAIC Screen pixelation xxxxabcd xxxxx=pixel size abcd=affect background layer
w $2107 BG1SC BG1 Tilemap VRAM location xxxxxxab xxx=address ab SC size 00=32x32 01=64x32 10=32x64 11=64x64
w $2108 BG2SC BG2 Tilemap VRAM location xxxxxxab xxx=address ab SC size 00=32x32 01=64x32 10=32x64 11=64x65
w $2109 BG3SC BG3 Tilemap VRAM location xxxxxxab xxx=address ab SC size 00=32x32 01=64x32 10=32x64 11=64x66
w $210A BG4SC BG4 Tilemap VRAM location xxxxxxab xxx=address ab SC size 00=32x32 01=64x32 10=32x64 11=64x67
w $210B BG12NBA BG1 & BG2 VRAM location aaaabbbb aaa=base addr for BG2 bbb=base addr for BG1
w $210C BG34NBA BG3 & BG4 VRAM location aaaabbbb aaa=base addr for BG4 bbb=base addr for BG3
wd $210D BG1HOFS BG1 horizontal scroll mmmmmaaa aaaaaaaa aaa=horiz offset, mmm=Mode 7 option
wd $210E BG1VOFS BG1 vertical scroll

wd $210F BG2HOFS BG2 horizontal scroll

wd $2110 BG2VOFS BG3 vertical scroll

wd $2111 BG3HOFS BG3 horizontal scroll - Same as $210D.
wd $2112 BG3VOFS BG3 vertical scroll

wd $2113 BG4HOFS BG4 horizontal scroll

wd $2114 BG4VOFS BG4 vertical scroll

w $2115 VMAIN Video port contro l i000abcd I 1=inc on $2118 or $2139 0=$2119 or $213A abcd=move size
w 2 $2116-$2117 VMADDL/H Video port address LLLLLLLL HHHHHHHH Memory address (in bytepairs)$0000-$7FFF
w 2 $2118-$2119 VMDATAL/H Video port data LLLLLLLL HHHHHHHH Byte Data
w $211A M7SEL MODE7 settings ab0000yx ab=out of area function x=xflip y=yflip
w $211B M7A COS rotate angle / X Expnsn

w $211C M7B SIN rotate angle / X Expnsn

w $211D M7C SIN rotate angle / Y Expnsn

w $211E M7D COS rotate angle / Y Expnsn

wd $211F M7X Center position X (13-bit data only)

wd $2120 M7Y Center position Y (13-bit data only)

w $2121 CGADD Colour # (or pallete) selection xxxxxxxx x=color (0-255)
wd $2122 CGDATA Colour data -bbbbbgg gggrrrrr Color Data BGR
w $2123 W12SEL Window mask settings abcdefgh
w $2124 W34SEL Window mask settings abcdefgh
w $2125 WOBJSEL Window mask settings abcdefgh
w $2126 WH0 Window 1 left position aaaaaaaa a=position
w $2127 WH1 Window 1 right position

w $2128 WH2 Window 2 left position - Same as $2126.
w $2129 WH3 Window 2 right position

w $212A WBGLOG Mask logic cfg for Win 1 & 2 per scr aabbccdd aa..dd=BG 4321
w $212B WOBJLOG Mask logic for Colour Win & OBJ Win 0000aabb a=color params b=obj window params
w $212C TM Main screen designation ---S4321 S=sprites 4-1=enable Bgx
w $212D TD Sub-screen designation *** Same as $212C
w $212E TMW Window mask main screen desig *** Same as $212C
w $212F TSW Window mask sub screen desig *** Same as $212C
w $2130 CGWSEL Fixed color addition or screen addition abcd00ef ab=main cd=sub ef=color data
w $2131 CGADSUB Addition/subtraction for screens mrgsabcd & OBJs [CGADSUB]
w $2132 COLDATA Fixed colour data for fixed colour +/- bgrdddddd Blue Green Red dddd=constant
w $2133 SETINI Screen mode/video select sn00pvshi
r $2134 MPYL Multiplication result (low)

r $2135 MPYM Multiplication result (middle)

r $2136 MPYH Multiplication result (high)

r $2137 SLHV Software latch for H/V counter aaaaaaaa a=result
r $2138 OAMDATAREAD Read data from OAM

r 2 $2139 VMDATAL/HREAD Read data from VRAM

r $213B CGDATAREAD Read data from CG-RAM (colour)

r d $213C OPHCT Horizontal scanline location

r d $213D OPVCT Vertical scanline location

r $213E STAT77 PPU status flag & version number trm0vvvv
r $213F STAT78 PPU status flag & version number fl0mvvvv
rw $2140 APUI00 APUI00 Sound Port 0

rw $2141 APUI01 APUI01 Sound Port 1

rw $2142 APUI02 APUI02 Sound Port 2

rw $2143 APUI03 APUI03 Sound Port 3

rw $2180 WMDATA Read/write WRAM

rw $2181 WMADDL WRAM data (low byte)

rw $2182 WMADDM WRAM data (middle byte)

rw $2183 WMADDH WRAM data (high byte)

rw $4016 JOYWR/JOYA Joypad Output / JOY 1 Read (bit 0 x12)

r $4017 JOYB JOY 2 Read (bit 0 x12)

w $4200 NMITIMEN Counter enable a0yx000b
w $4201 WRIO Programmable I/O port (out-port)

w $4202 WRMPYA Multiplicand 'A'

w $4203 WRMPYB Multiplier 'B

w 2 $4204 WRDIVL/H Dividend C

w $4205 WRDIVB Divisor B

w 2 $4207 HTIMEL/H Video H IRQ beam pos/pointer 0000000x xxxxxxxx x: Beam position.
w 2 $4209 VTIMEL/H Video V IRQ beam pos/pointer 0000000y yyyyyyyy y: Beam position.
w $420B MDMAEN DMA enable 76543210
w $420C HDMAEN HDMA enable .

w $420D MEMSEL Cycle speed 0000000x 0=2.68 1=3.58
r $4210 RDNMI NMI x000vvvv x=disable NMI v=version
rw $4211 TIMEUP Video IRQ i0000000 i=irq enabled
rw $4212 HVBJOY Status xy00000a x=vblank state y=hblank state a=joypad ready
r $4213 RDIO Programmable I/O port (in-port)

r 2 $4214 RDDIVL/H Quotient of divide result

r 2 $4216 RDMPYL/H Multiplication or divide result

r $4218 JOY1L Joypad #1 status (set during interrupt) AXLR----
r $4219 JOY1H Joypad #1 status (if $4200 is set) BYSTUDLR
r $421A JOY2L Joypad #2 status AXLR----
r $421B JOY2H Joypad #2 status BYSTUDLR
r $421C JOY3L Joypad #3 status AXLR----
r $421D JOY3H Joypad #3 status BYSTUDLR
r $421E JOY4L Joypad #4 status AXLR----
r $421F JOY4H Joypad #4 status BYSTUDLR
w $43x0 DMAPX DMA Control vh0cbaaa
w $43x1 BBADX DMA Destination LLLLLLLL H=$21
w 2 $43x2 A1TXL/H Source address

w $43x4 A1BX Source bank address

w 2 $43x5 DASXL/H DMA transfer size & HDMA address

w $43xA NTRLX Number of lines for HDMA transfer cxxxxxxx C=continue (0=yes) x=lines to transfer

 

View Options
Default Dark
Simple (Hide this menu)
Print Mode (white background)

Top Menu
Youtube channel
ASM Programming Forums
GitHub
Dec/Bin/Hex/Oct/Ascii Table

Z80 Content
Learn Z80 Assembly
Hello World
Advanced Series
Multiplatform Series
Platform Specific Series
ChibiAkumas Series
Grime Z80
Z80 Downloads
Z80 Cheatsheet
Sources.7z
DevTools kit
Z80 Platforms
Amstrad CPC
Elan Enterprise
Gameboy & Gameboy Color
Master System & GameGear
MSX & MSX2
Sam Coupe
TI-83
ZX Spectrum
Spectrum NEXT
Camputers Lynx

6502 Content
Learn 6502 Assembly
Advanced Series
Platform Specific Series
Grime 6502
6502 Downloads
6502 Cheatsheet
Sources.7z
DevTools kit
6502 Platforms
Apple IIe
Atari 800 and 5200
Atari Lynx
BBC Micro
Commodore 64
Commander x16
Super Nintendo (SNES)
Nintendo NES / Famicom
PC Engine (Turbografx-16)
Vic 20

68000 Content
Learn 68000 Assembly
Platform Specific Series
Grime 68000
68000 Downloads
68000 Cheatsheet
Sources.7z
DevTools kit
68000 Platforms
Amiga 500
Atari ST
Neo Geo
Sega Genesis / Mega Drive
Sinclair QL (Quantum Leap)
X68000 (Sharp x68k)

8086 Content
Learn 8086 Assembly
8086 Downloads
8086 Cheatsheet
Sources.7z
DevTools kit
8086 Platforms
Wonderswan
MsDos

ARM Content
Learn ARM Assembly
ARM Downloads
ARM Cheatsheet
Sources.7z
DevTools kit
ARM Platforms
Gameboy Advance
Risc Os

Risc-V Content
Learn Risc-V Assembly
Risc-V Downloads
Risc-V Cheatsheet
Sources.7z
DevTools kit

PDP-11 Content
Learn PDP-11 Assembly
PDP-11 Downloads
PDP-11 Cheatsheet
Sources.7z
DevTools kit

My Game projects
Chibi Aliens
Chibi Akumas

Work in Progress
Learn 6809 Assembly
Learn 65816 Assembly
Learn 6809 Assembly
Learn TMS9900 Assembly
Dragon 32/Tandy Coco
Ti 99

Misc bits
Ruby programming













































If you want to support my work, please consider backing me on patreon!










Buy Chibi Akuma(s) from PolyPlay
Buy ChibiAkuma(s) games now!



































































































































































































































If you want to support my work, please consider backing me on patreon!










Buy Chibi Akuma(s) from PolyPlay
Buy ChibiAkuma(s) games now!



































































































































































































































If you want to support my work, please consider backing me on patreon!










Buy Chibi Akuma(s) from PolyPlay
Buy ChibiAkuma(s) games now!