Page 1 of 1

n00b SNESdev questions

Posted: Wed Sep 08, 2010 5:01 am
by artakserkso
Okay, here's some code I threw together with help of Bazz's tutorial (available here). In bsnes it works fine, so I thought it should work on the SNES PowerPak after a quick ucon64 -padn=524288. It doesn't.

The point is showing a Mario sprite in the middle of the screen and doing nothing until Right on the D-pad is pressed. That's when the Mario sprite should do... Guess what! :D

So far I've had no trouble with padding something small/homebrew for the PowerPak and getting it to run (for example, when I had no joypad code and only wanted to put Mario on screen).

This time Mario either pops up on screen, does nothing when I press anything and after a while dissapears off screen. Huh?! Sometimes when I reset or recopy the code from CF, he doesn't appear on screen at all. I'm very puzzled by all this.

Anyway, here's the code. Also, any good programming tips I might be able to use are highly appreciated. Sorry for the code being messy as all hell.

Code: Select all

.INCLUDE "header.inc"
.INCLUDE "initsnes.asm"

.MACRO LoadPalette		;DMA transfers a palette to CGRAM (A:8b,XY:16b)
	lda #\2		     	;args: 24b source, 8b dest, 8b number of colors
	sta $2121
	lda #:\1
	ldx #\1
	ldy #(\3*2)
	jsr DMAPalette
.ENDM

.MACRO LoadBlockToVRAM		;DMA transfers a block to VRAM (A:8b,XY:16b)
	ldx #\2			         ;args: 24b source, 16b dest, 8b size in bytes
	stx $2116
	lda #:\1
	ldx #\1
	ldy #\3
	jsr LoadVRAM
.ENDM

.BANK 0 SLOT 0
.ORG 0


.ENUM $0002
Joy1Raw     DW      ; Holder of RAW joypad data from register (from last frame)
Joy2Raw     DW

Joy1Press   DW      ; Contains only pressed buttons (not held down)
Joy2Press   DW

Joy1Held    DW      ; Contains only buttons that are Held
Joy2Held    DW

 .ENDE

	
.SECTION "Main"
	
Start:
	InitSNES
	lda #$80
	sta $4200
	lda #$80		                           ;don't increment VRAM address until written to $2119
	sta $2115	                             ;(as opposed to $2118)
	LoadPalette SprPal, 128, 16              ;sprite palettes start at 128
	LoadBlockToVRAM Sprite, $0000, $0800
	jsr SpriteInit
	lda #(256/2-16)
	sta $0000
	lda #(224/2-16)
	sta $0001
	lda #%01010100
	sta $0200
	jsr SetupVideo
	
loop:
	wai
	lda Joy1Press+1
	and #$01
	beq loop
	inc $0000
	inc $0000
 	jmp loop

SetupVideo:
	php
	rep #$10
	sep #$20
	stz $2102
	stz $2103
	ldy #$0400
	sty $4300
	stz $4302
	stz $4303
	lda #$7E
	sta $4304
	ldy #$0220
	sty $4305
	lda #$01
	sta $420B
	lda #%10100000
	sta $2101
	lda #%00010000
	sta $212C
	lda #$0F
	sta $2100
	plp
	rts

LoadVRAM:			;initiates DMA transfer to VRAM
	php
	stx $4302
	sta $4304
	sty $4305
	lda #$01
	sta $4300		;first write to $2118, then $2119, then $2118...
	lda #$18
	sta $4301
	lda #$01
	sta $420B
	plp
	rts
	
DMAPalette:		 ;initiates DMA transfer to CGRAM
	php
	stx $4302
	sta $4304
	sty $4305
	stz $4300		;only write to $2122
	lda #$22
	sta $4301
	lda #$01
	sta $420B
	plp
	rts

SpriteInit:		 ;move all sprites off screen
	php
	rep #$30
	ldx #$0000
	lda #$01
_offscreen:
	sta $0000,x
	inx
	inx
	inx
	inx
	cpx #$0200
	bne _offscreen

	lda #$5555
	ldx #$0000
_xsmb:
	sta $0200,x
	inx
	inx
	cpx #$0020
	bne _xsmb
	plp
	rts
	
VBlank:
	php
	jsr Joypad
	stz $2102
	stz $2103
	sep #$20
	lda $0000
	sta $2104
	lda $0001
	sta $2104
	plp
	rti

Joypad:
	php
	rep #$30
	lda $4212
	and #$01
	beq Joypad
	lda #$81
	sta $4200
	ldx Joy1Raw
	lda $4218
	sta Joy1Raw
	txa
	eor Joy1Raw
	and Joy1Raw
	sta Joy1Press
	txa
	and Joy1Raw
	sta Joy1Held
	plp
	rts	
.ENDS
	
.BANK 1 SLOT 0
.ORG 0
.SECTION "CharacterData"
Sprite:
	.INCBIN "biker.pic"

SprPal:
	.INCBIN "biker.clr"
.ENDS

Posted: Wed Sep 08, 2010 5:41 am
by mic_
I didn't do a full analysis so there may be other problems as well, but this:

Code: Select all

Joypad:
   php
   rep #$30
   lda $4212
   and #$01
   beq Joypad 
does not seem like a good idea, since you could end up trashing the stack completely by having the PHP instruction inside the loop.

Posted: Wed Sep 08, 2010 7:38 am
by artakserkso
I knew it was something ridiculous, but this... :shock:

Thanks, mic_!

I have to be more careful with the P reg...

Btw, Mario moves a bit differently than I would have expected him to. If I tap Right fairly quickly (without trying too much), but at constant speed, Mario only moves once every two taps. Also, when I press and hold Right, he moves every half-second or so.

In bsnes, however, pressing and holding Right only moves him once and tapping quickly really does move him as many times as I tap (this behaviour is what I would expect and like). Guess that must have something to do with cycles and my taking care of VBlank/the Joypad routine improperly.

Posted: Wed Sep 08, 2010 8:06 am
by tepples
If you enable automatic joypad reading (bit 0 of $4200 = 1), it takes about three scanlines after vertical blank for the bits of $4218-$421F to settle. So do your DMA transfers to VRAM and wait for the controller reads to finish (that is, wait for bit 0 of $4212 to become 0) before you read them.

Posted: Wed Sep 08, 2010 8:49 am
by artakserkso
Ah, right... You only need to set bit 0 of $4200 once. Noted.

Also, I already had the wait for joypad stuff. But I accidentally put rep #$30 after the check, which probably meant I waited too long from when the joypad was ready to actually reading it.

Thanks, tepples, it now works as it should!

Posted: Thu Sep 09, 2010 6:28 pm
by Near
In bsnes, however, pressing and holding Right only moves him once and tapping quickly really does move him as many times as I tap (this behaviour is what I would expect and like).
You mean it works differently on real hardware?

Yeah, that's most likely auto joypad polling. It strobes the controller between V=225 to V=227, bit-by-bit. But unfortunately nobody knows how that strobe works. blargg looked into the timing for me, but it turns out to be ridiculously complex.

At the moment, I do all the polling at V=227. So if you read at V=225 with that on, you're basically getting the previous frames' completed state, whereas on the real thing you'd get weird data back.

There's a small number of things even I can't do yet:
- auto joypad polling
- CPU revision 1 HDMA<>DMA conflict crashing
- CPU<>SMP bus conflict issues
- CGRAM/OAM writes mid-scanline going to the wrong addresses
- SMP test register has two timing bits, and r1 has a rare timer glitch
- DSP has a mute pulse, not an instant mute
- initial memory states are not 'randomized' like the real thing
- PPU doesn't always cache registers at the right times for mid-scanline writes

Outside of those issues, and bugs we don't even know about yet, it should be perfect.

Posted: Fri Sep 10, 2010 3:44 am
by artakserkso
Thanks a lot for the inside info, byuu, that's always great to hear!

I hope some day the issues you mentioned get sorted out.

By the way, bsnes is fantastic. It really helps when I have to test my code. I absolutely adore the debugger. Without the memory editor, I'm completely certain I'd never be able to understand why my code fails at first.

Keep up the good work!