Page 1 of 2

SNES programming beginner needs code review

Posted: Wed Apr 26, 2017 2:42 pm
by melanokardios
I started writing code for SNES for the first time today, though I've written a pong clone for NES once.

So I got myseld the SNES Programming Manual that is floating around the web and wrote a simple initialisation routine and basic code, that will display a green screen(most SNES tutorials seem to start with this).

Alas, my code won't work. After one hour of checking and re-checking my init routine, I turn to you in hope of finding someone who will find my error.

I work with the ca65 assembler, since I used that for my NES programming and I'm most comfortable with it.

so, here goes my code.

My "main" file:

Code: Select all

; my first SNES ROM
.p816   ; 65816 processor
.i16    ; X/Y are 16 bits
;.a8     ; A is 8 bits

.segment "ROMREG"
    .include "RomRegisterData.inc"

.segment "VECTORS"
    .word 0, 0, 0, 0, 0, 0, 0, 0
    .word 0, 0, 0, 0, 0, NMI, reset, 0

.segment "CODE"
    .include "SNESInit.asm"
    .include "tiles.inc"

reset:
    jsr InitSNES

    ; set background to green
    lda #$1f
    sta $2122
    lda #$00
    sta $2122

    ; Max screen brightness
    lda #$0f
    sta $2100

forever:
    jmp forever

NMI:
    rti 
my initalisation routine(I guess the error is somewhere here):

Code: Select all

; init SNES according to SNES Programming Manual chapter 23
    .include "SNESRegisters.inc"
;----------------------------------------------------------
InitSNES:
    ; basic pre-init setup
    sei             ; disable interrupts
    clc             ; switch to...
    xce             ; ...native mode

    rep #$38        ; X,Y and A are 16 bits, decimal mode off

    ldx #$1fff      ; set up stack
    txs

    lda #$0000      ; set Data Register to zero
    tcd 

    ; turn on forced blanking / turn of screen
    sep #$20        ; A is 8 bits
    lda #$8F
    sta INIDISP
    ;rep #$20        ; A is 16 bits
    
    ; clear Registers
    phk             ; Data Bank = Program Bank
    plb

    ldx #$2101
loop00:             ; Regs $2101 - $210c
    stz $00,x
    inx
    cpx #$210d
    bne loop00 

loop01:             ; Regs $201d - $2114
    stz $00,x 
    stz $00,x 
    inx 
    cpx #$2115
    bne loop01 

    lda #$80        ; set VRAM mode
    sta $2115

    stz $2116
    stz $2117

        ; $2118 and $2119 need no initialisation

    stz $211a

    ldx #$211b
loop03:             ; Regs $211b - $2120
    stz $00,x
    stz $00,x 
    inx 
    cpx #$2121
    bne loop03 

    stz $2121

        ; $2122 need no initialisation
    
    ldx #$2123
loop04:             ; Regs $2123 - $2133
    stz $00,x 
    inx 
    cpx #$2134
    bne loop04 

    ldx #$4200
loop05:             ; Regs $4200 - $420d
    stz $00,x 
    inx 
    cpx #$420e
    bne loop05 

    lda #$30        ; turn on fixed color addition
    sta $2130

    lda #$e0        ; turn on RGB
    sta $2132

    lda #$ff        ; turn on I/O port
    sta $4201

    ; set Main Registers
    ;lda #$1f        ; turn on all BGs and OBJ
    ;sta $212c

    ; set BG1 - 4 and OBJ

    ; OAM, CG Data setting with DMA
    jsr InitOAMandCG

    ; VRAM Data setting with DMA
    jsr InitVRAM

    ; release forced blanking
    lda #$0F
    sta INIDISP

    ; enable NMI and standard controller
    lda #$81
    sta $4200
    cli 

    rts 

;----------------------------------------------------------
; init OAM and CG RAM
InitOAMandCG:
    rts

;----------------------------------------------------------
; init VRAM
InitVRAM:
    rts 
Those are the two most important files. Here are the other two mentioned.

SNESRegisters.inc (I plan to expand this...)

Code: Select all

; register aliases

INIDISP             = $2100
ROMRegisterData.inc

Code: Select all

; ROM Registration Data as specified in SNES Manual 1-2-25

.word       $ffff               ; maker code
.byte       $47, $52, $45, $4e  ; game code
.byte       $00, $00, $00, $00, $00, $00, $00
.byte       $00                 ; no expansion RAM
.byte       $00                 ; no special version
.byte       $00                 ; no special/sub cartridge
.byte       "MY FIRST TILES"    ; game title
.byte       $20, $20, $20, $20  ; game title fill
.byte       $30                 ; high speed, Mode 20
.byte       $00                 ; ROM only cartridge
.byte       $07                 ; 1Mb/128kB, NOT DOCUMENTED
.byte       $00                 ; 0B, no RAM
.byte       $00                 ; Japan
.byte       $33                 ; fixed value
.byte       $00                 ; revision number
.word       $aaaa               ; checksum
.word       $5555               ; complement checksum

Any help is greatly welcomed.

Re: SNES programming beginner needs code review

Posted: Wed Apr 26, 2017 2:52 pm
by nicklausw
Could you post your cfg file for ld65?

Re: SNES programming beginner needs code review

Posted: Wed Apr 26, 2017 2:55 pm
by melanokardios
nicklausw wrote:Could you post your cfg file for ld65?
Yes, forgot that one, it's pretty basic:

Code: Select all

# minimal SNES cartridge

MEMORY {
    ROM1:   start = $8000, size = $200000, fill = yes;
}

SEGMENTS {
    CODE:       load = ROM1,    align = $8000;
    ROMREG:     load = ROM1,    start = $ffb0;
    VECTORS:    load = ROM1,    start = $ffe0;
}

I even made a makefile:

Code: Select all

CC = ca65
LD = ld65
LDCONF = -C lorom128.cfg
OBJECTS = MyFirstTile.o

MyFirstTile.smc: $(OBJECTS)
	$(LD) $(LDCONF) $(OBJECTS) -o $@

MyFirstTile.o: MyFirstTile.asm
	$(CC) $<

clean:
	rm *.o *.smc

Re: SNES programming beginner needs code review

Posted: Wed Apr 26, 2017 2:55 pm
by niconii
I notice that your init code already turns off forced blanking. That might be interfering with your writes to $2122, since they're probably not happening during Vblank/Hblank.

Re: SNES programming beginner needs code review

Posted: Wed Apr 26, 2017 2:59 pm
by melanokardios
Nicole wrote:I notice that your init code already turns off forced blanking. That might be interfering with your writes to $2122, since they're probably not happening during Vblank/Hblank.
True, I moved it to NMI/VBlank, to no avail. Still a black screen.

Re: SNES programming beginner needs code review

Posted: Wed Apr 26, 2017 3:05 pm
by niconii
Another problem I see is that you use jsr to call your init code, but that's where you set up the stack, so rts won't return you back where you were, because the stack pointer is no longer pointing at the address you need to return to.

You should probably jmp to the init code, and jmp back instead. Alternatively, you could just have the vector point straight to InitSNES, and then jmp reset at the end of your init code.

Re: SNES programming beginner needs code review

Posted: Wed Apr 26, 2017 3:24 pm
by melanokardios
Nicole wrote:Another problem I see is that you use jsr to call your init code, but that's where you set up the stack, so rts won't return you back where you were, because the stack pointer is no longer pointing at the address you need to return to.

You should probably jmp to the init code, and jmp back instead. Alternatively, you could just have the vector point straight to InitSNES, and then jmp reset at the end of your init code.
I did try that before, neither jmp nor jsr won't do the trick. I even tried moving all of the code into on file to avoid both op codes - still nothing.

I probably missed some small detail about how registers on the SNES work, the programming manual has a weird structure. Maybe I'll try to re-write one of the tutorials I found to work on ca65/ld65, that might help.

Re: SNES programming beginner needs code review

Posted: Wed Apr 26, 2017 3:31 pm
by nicklausw
Not entirely sure if this is the problem but try using .smart at the beginning of your code. It tracks REPs and SEPs to properly size opcodes, whereas your code seems to assume that A is always 8 bit and X,Y are always 16 bit. A changes size during the init routine which could mess everything up.

Re: SNES programming beginner needs code review

Posted: Wed Apr 26, 2017 3:36 pm
by nicklausw
Another thing, your header has the title set to 18 bytes instead of 21. Fixing this made a red screen come up, not sure why that's happening but it's better than what was showing up before.

Re: SNES programming beginner needs code review

Posted: Wed Apr 26, 2017 3:43 pm
by niconii
The color #$001f is in fact red, not green, and that's what's being written, so it sounds like it's actually working in that case.

Re: SNES programming beginner needs code review

Posted: Wed Apr 26, 2017 3:46 pm
by melanokardios
nicklausw wrote:Another thing, your header has the title set to 18 bytes instead of 21. Fixing this made a red screen come up, not sure why that's happening but it's better than what was showing up before.
A red screen is what I want! I changed my header, but it still won't work, what emulator do you use?

Re: SNES programming beginner needs code review

Posted: Wed Apr 26, 2017 3:50 pm
by nicklausw
After changing the starting vector to InitSNES jumping to reset, turning on smart mode, changing the name size and changing the ROM type in the header from $30 to $20 (you had it set to HiROM, I believe?), the code functions properly.

Not sure what emulator you're using but I recommend bsnes-plus. Its debugger is why I didn't say "the code works!" when the screen is red but the code is a constant loop of brk $00.

Re: SNES programming beginner needs code review

Posted: Wed Apr 26, 2017 4:01 pm
by niconii
nicklausw wrote:changing the ROM type in the header from $30 to $20 (you had it set to HiROM, I believe?)
Nah, $30 means fast LoROM, versus $20 for slow LoROM (whereas HiROM is $21 or $31). Having $30 there shouldn't be an issue.

Re: SNES programming beginner needs code review

Posted: Wed Apr 26, 2017 4:02 pm
by melanokardios
Wow, thank you! I never used .smart before, since it is my first 65816 code. A quick look up in the ca65 doc tells me I probably need to study the registers/architecture of the 65816 better - my guess right now is, I'm not using Data Bank and Program Bank registers properly.

That would also explain why PC keeps pointing to $00 / BRK.

Again, thank you all for your suggestions, you've been all very helpful! :P

Re: SNES programming beginner needs code review

Posted: Wed Apr 26, 2017 4:09 pm
by nicklausw
Nicole wrote:
nicklausw wrote:changing the ROM type in the header from $30 to $20 (you had it set to HiROM, I believe?)
Nah, $30 means fast LoROM, versus $20 for slow LoROM (whereas HiROM is $21 or $31). Having $30 there shouldn't be an issue.
Oh yeah, I thought there was a difference because I forgot to rebuild after changing the header...

Which brings me to a piece of advice, make sure your makefiles are aware of the reliance on your .inc files. Should be a quick %.s: %.inc and adding %.s as a dependency on your ROM.

Another tip that's pretty minor and more of a personal thing but I might as well mention it, please use the .sfc format instead of .smc. .smc is an old copier format that originally had a 512-byte header in front of it, but it doesn't seem to now, and the inconsistency is pretty gross so I'd rather everyone just use .sfc.