Writing your own SNES initialization routine from scratch?

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Writing your own SNES initialization routine from scratch?
by on (#200714)
Hey there. I've been looking into SNES homebrew recently, and I noticed that while there are a great number of premade initialization procedures available for various different assemblers, there doesn't seem to be a clear, concise list of instructions regarding how to actually set up the SNES at boot from scratch.

Every tutorial I've seen simply glosses over the routine, provides a source file, and tells you not to worry about it, but I personally don't like randomly including a piece of black-box code to my program when I have no idea what it even does. Any forum posts I can find seem to take initialization as a solved problem, or refer to an unspecified section of the SNES Development Guide which I cannot seem to find.

Are there any resources available that provide detailed information about initialization, am I missing something obvious, or am I out of luck on this front? Thanks in advance for your help.
Re: Writing your own SNES initialization routine from scratc
by on (#200715)
It's not wrong to sit down with goodsnesfullsnes and tepples's initialization code and work out what it's doing.

My understanding is that every register in the PPU can power up with semirandom contents that will make random things not work if you don't do the full manual initialization, even if it's not obviously related in any way to your code. Hence the admonition to "just copy this and don't worry about it" is because it's tempting to think "Why do I need to initialize register X" and then something inscrutable doesn't work.
Re: Writing your own SNES initialization routine from scratc
by on (#200716)
"GoodSNES" is a ROM image auditing tool by Cowering. Did you mean Fullsnes, the comprehensive Super NES programming document by Martin "nocash" Korth?

I'll take this as a feature request to comment every write in my init.s with what it does.

EDIT: A few pushes later, all initialization is documented.
Re: Writing your own SNES initialization routine from scratc
by on (#200733)
I imagine another reason guides tend to gloss over it is that, since it involves setting up basically every register in the system, to fully understand it you more-or-less have to understand the whole system already. A full breakdown of exactly what the init code is doing isn't a great thing to start a guide off with if you just want to start with basics and build up from there.
Re: Writing your own SNES initialization routine from scratc
by on (#200763)
A little bird told me that Nintendo's official SNES development docs have a thorough description of how to initialize the system.
Re: Writing your own SNES initialization routine from scratc
by on (#200769)
I appreciate all of your replies.
lidnariq wrote:
My understanding is that every register in the PPU can power up with semirandom contents that will make random things not work if you don't do the full manual initialization, even if it's not obviously related in any way to your code. Hence the admonition to "just copy this and don't worry about it" is because it's tempting to think "Why do I need to initialize register X" and then something inscrutable doesn't work.
Nicole wrote:
I imagine another reason guides tend to gloss over it is that, since it involves setting up basically every register in the system, to fully understand it you more-or-less have to understand the whole system already. A full breakdown of exactly what the init code is doing isn't a great thing to start a guide off with if you just want to start with basics and build up from there.
That figures - I just thought that the init procedure would be slightly better documented, seeing as every game has to perform it in some fashion.
thefox wrote:
A little bird told me that Nintendo's official SNES development docs have a thorough description of how to initialize the system.
Would said little bird happen to have a page number? Perhaps I have the wrong development documentation.
tepples wrote:
I'll take this as a feature request to comment every write in my init.s with what it does.
This has probably been the most helpful resource so far - no terribly cryptic comments, and all contained within one file. Thank you for putting this together, tepples!
Re: Writing your own SNES initialization routine from scratc
by on (#200774)
voynich wrote:
thefox wrote:
A little bird told me that Nintendo's official SNES development docs have a thorough description of how to initialize the system.
Would said little bird happen to have a page number? Perhaps I have the wrong development documentation.

Bird says: Book I, Section 2, Chapter 26 (p. 2-26-1). It doesn't go into a lot of detail about why the registers are initialized this way, but it's quite obvious (0 for most of the registers, special values for a few of them, "why" mostly explained by looking at the register descriptions).
Re: Writing your own SNES initialization routine from scratc
by on (#200791)
thefox wrote:
--snip--
Bird says: Book I, Section 2, Chapter 26 (p. 2-26-1). It doesn't go into a lot of detail about why the registers are initialized this way, but it's quite obvious (0 for most of the registers, special values for a few of them, "why" mostly explained by looking at the register descriptions).
Oh, that's fantastic! Exactly the sort of thing I was looking for. Thank you (and your brilliant bird) very much.
Re: Writing your own SNES initialization routine from scratc
by on (#200825)
voynich wrote:
I just thought that the init procedure would be slightly better documented, seeing as every game has to perform it in some fashion.

They don't necessarily have to - there are a few known cases of games relying on uninitialized memory.
Re: Writing your own SNES initialization routine from scratc
by on (#200858)
I threw some comments on the INIT code from https://wiki.superfamicom.org/snes/show ... ES+Program
if that will help.

;----------------------------------------------------------------------------
; InitSNES -- my "standard" initialization of SNES memory and registers
;----------------------------------------------------------------------------
.MACRO InitSNES
sei ;disable IRQ interrupts
clc ;switch to native mode
xce
;the 65816 processor start off in 6502 emulation mode, clc xce must be used to go to 65816 mode

REP #$38 ; mem/A = 16 bit, X/Y = 16 bit
;decimal mode off

LDX #$1FFF ;Setup the hardware stack, the stack goes downward from here
TXS ;Transfer Index X to Stack Pointer Register

;do the rest of the initialization in a routine
JSL $008000

SEP #$20 ; mem/A = 8 bit
.ENDM

;----------------------------------------------------------------------------

.BANK 0 SLOT 0
.ORG 0
.SECTION "InitializeSNESCode" FORCE

InitializeSNES:
PHK ;set Data Bank = Program Bank
PLB
;K is the bank of the running program code
;B is the bank of the data for read/writes that don't use long addresses
;PHK pushes the current K (= 00) to the stack, and the PLB pulls it to B

LDA #$0000 ;set Direct Page = $0000
TCD ;Transfer Accumulator to Direct Register

LDX $1FFD ;we clear all the mem at one point ...
STX $4372 ;so save the return address in a place that won't get overwritten
LDX $1FFF
STX $4374
;unusual, using some DMA registers as temporary storage of the return address from the stack

SEP #$20 ; mem/A = 8 bit
REP #$10

LDA #$8F
STA $2100 ;turn screen off for now, set brightness to normal
;1000 0000 is forced blank mode, to allow multiple writes to the VRAM / PPU
;I would have turned brightness to zero here, but whatever
;a little later, forced blanking must be turned OFF to allow rendering


LDX #$2101
_Loop00: ;store zero to regs $2101-$210C
STZ $00,X ;set Sprite,Character,Tile sizes to lowest, and set addresses to $0000
INX
CPX #$210D
BNE _Loop00

;2101 Object Size and Character Size Register -sets sprites to 8x8 or 16x16, tiles at VRAM 0000
;2102 OAM Address Registers (Low) -sets an address for sprite memory
;2103 OAM Address Registers (High)
;2104 OAM Data Write Register -not particularly useful, writing just one byte to the OAM
;2105 BG Mode and Character Size Register - sets Mode 0 BGs = 4 layers of 2bpp(4color), 8x8 tiles, same as NES
;2106 Mosaic Register -turn off
;2107 BG Tilemap Address Registers (BG1) - tells the PPU to use address $0000 for bg1 tilemap
;2108 BG Tilemap Address Registers (BG2) - tells the PPU to use address $0000 for bg2 tilemap
;2109 BG Tilemap Address Registers (BG3) - tells the PPU to use address $0000 for bg3 tilemap
;210a BG Tilemap Address Registers (BG4) - tells the PPU to use address $0000 for bg4 tilemap
;210b BG Character Address Registers (BG1&2) - tells the PPU to use address $0000 for tiles bg1 and bg2
;210c BG Character Address Registers (BG3&4) - tells the PPU to use address $0000 for tiles bg3 and bg4
; you, of course, won't want to put tiles and tilemaps at the same location in the VRAM

_Loop01: ;regs $210D-$2114, these registers are 2 writes per register
STZ $00,X ;Set all BG scroll values to $0000
STZ $00,X
INX
CPX #$2115
BNE _Loop01

;210d BG Scroll Registers (BG1) - horizontal
;210e BG Scroll Registers (BG1) - vertical
;210f BG Scroll Registers (BG2) - horizontal
;2110 BG Scroll Registers (BG2) - vertical
;2111 BG Scroll Registers (BG3) - horizontal
;2112 BG Scroll Registers (BG3) - vertical
;2113 BG Scroll Registers (BG4) - horizontal
;2114 BG Scroll Registers (BG4) - vertical
;-set all to 0,0

LDA #$80 ;reg $2115
STA $2115 ; Initialize VRAM transfer mode to word-access, increment by 1

STZ $2116 ;regs $2117-$2117
STZ $2117 ;sets an address in the VRAM = $0000

;reg $2118-$2119
;VRAM write register... don't need to initialize

STZ $211A ;clear Mode7 setting

LDX #$211B
_Loop02: ;regs $211B-$2120
STZ $00,X ;clear out the Mode7 matrix values
STZ $00,X
INX
CPX #$2121
BNE _Loop02

;reg $2121 - Color address, doesn't need initilaizing (CGRAM is the palette)
;reg $2122 - Color data, is initialized later

LDX #$2123
_Loop03: ;regs $2123-$2133
STZ $00,X ;turn off windows, main screens, sub screens, color addition,
INX ;fixed color = $00, no super-impose (external synchronization),
CPX #$2134 ;no interlaced mode, normal resolution
BNE _Loop03

;2123 - Window Mask Settings Registers - BG 1 & 2 - turn off windowing
;2124 - Window Mask Settings Registers - BG 3 & 4 - turn off windowing
;2125 - Window Mask Settings Registers - OBJ (sprites) & Fixed BG Color
;2126 - Window Position Registers (WH0)
;2127 - Window Position Registers (WH1)
;2128 - Window Position Registers (WH2)
;2129 - Window Position Registers (WH3)
;212a - Window Mask Logic registers (BG)
;212b - Window Mask Logic registers (OBJ)
;- windowing prevents rendering on certain parts of the screen

;212c - Main Screen Destination Registers
; ! NOTE - at least one thing must be turned ON on the Main Screen to render an actual screen
;212d - Sub Screen Destination Registers
;212e - Main Screen -Window Mask Destination Registers
;212f - Sub Screen -Window Mask Destination Registers

;2130 - Color Math Select - blends main screen and subscreen, transparency effects
;2131 - Color Math Designation

;2132 - Fixed Color Data

;2133 - Screen Mode Select Register (hires mode, etc)


;regs $2134-$2136 - multiplication result, no initialization needed
;reg $2137 - software H/V latch, no initialization needed
;reg $2138 - Sprite data read, no initialization needed
;regs $2139-$213A - VRAM data read, no initialization needed
;reg $213B - Color RAM data read, no initialization needed
;regs $213C-$213D - H/V latched data read, no initialization needed

STZ $213E ;reg $213E - might not be necesary, but selects PPU master/slave mode
;reg $213F - PPU status flag, no initialization needed

;reg $2140-$2143 - APU communication regs, no initialization required

;reg $2180 - read/write WRAM register, no initialization required
;reg $2181-$2183 - WRAM address, no initialization required

;reg $4016-$4017 - serial JoyPad read registers, no need to initialize


STZ $4200 ;reg $4200 - disable timers, NMI,and auto-joyread

LDA #$FF
STA $4201 ;reg $4201 - programmable I/O write port, initalize to allow reading at in-port

;regs $4202-$4203 - multiplication registers, no initialization required
;regs $4204-$4206 - division registers, no initialization required

;regs $4207-$4208 - Horizontal-IRQ timer setting, since we disabled this, it is OK to not init
;regs $4209-$420A - Vertical-IRQ timer setting, since we disabled this, it is OK to not init

STZ $420B ;reg $420B - turn off all general DMA channels
STZ $420C ;reg $420C - turn off all H-MA channels

STZ $420D ;reg $420D - ROM access time to slow (2.68Mhz)

LDA $4210 ;reg $4210 - NMI status, reading resets

;reg $4211 - IRQ status, no need to initialize
;reg $4212 - H/V blank and JoyRead status, no need to initialize
;reg $4213 - programmable I/O inport, no need to initialize

;reg $4214-$4215 - divide results, no need to initialize
;reg $4216-$4217 - multiplication or remainder results, no need to initialize

;regs $4218-$421f - JoyPad read registers, no need to initialize

;regs $4300-$437F
;no need to intialize because DMA was disabled above
;also, we're not sure what all of the registers do, so it is better to leave them at
;their reset state value


;clear Sprite tables
STA $2104 ;set X = 240
STA $2104 ;set Y = 240 = offscreen

ClearVRAM:
;fills with zero, no tiles, no tilemap


ClearPalette:
;this just fills with zero, all black
Re: Writing your own SNES initialization routine from scratc
by on (#200874)
As I mentioned in a nearby topic, this routine does not correctly initialize the fixed color data ($2132). Loop03 should be changed to terminate earlier, and the values for $2132 and $2133 done separately outside the loop.

From the wiki, you write a byte of the form bgrccccc to $2132 where bgr indicates which color channels of the fixed color to modify. If bgr is 000 then no change will occur and the fixed color will remain at its randomized value.
Re: Writing your own SNES initialization routine from scratc
by on (#200904)
Is this a correct initialization?

With A in 8-bit mode

LDA #$e0
STA $2132
Re: Writing your own SNES initialization routine from scratc
by on (#200905)
It seems to work for me in bsnes-plus.

Don't forget to stz $2133 if you're shortening the loop.