Advice for an aspiring homebrewer?

Discussion of hardware and software development for Super NES and Super Famicom.

Moderator: Moderators

Forum rules
  • For making cartridges of your Super NES games, see Reproduction.
imamelia
Posts: 7
Joined: Wed Sep 01, 2010 12:17 am

Post by imamelia » Mon Sep 06, 2010 7:00 pm

MottZilla wrote:You can try being very organized in learning things. If that's what works best for you, go for it. Personally I find it's better to learn things as you need them, so you understand why you need them. Opposed to learning about something and not really using it, forgetting it, and then having to revisit it. But it depends on how you learn.
It will probably be a combination of both.
MottZilla wrote:If you get good at using the NES then stepping up to the SNES should be no problem.
Yeah...I imagine NES programming would be easier, but I already know the format and everything for 65816 ASM, so I don't see much point in going back to 6502. I'm also not as interested in the NES as I am in the SNES.
MottZilla wrote:I'm not sure if you have done much 65816 programming but atleast you have a bit of experience.
Well...I've done blocks, sprites (what would technically be called "objects"), and patches (editing existing code and sometimes splicing in new code), although I've never really done anything from scratch.
smkd wrote:And if you hit a wall somewhere, just post a thread detailing what you tried and what went wrong and someone will definitely help. You won't stay stuck for long since we have plenty of SNES devers here to help.
Well, that's good. I'm just afraid I'll get stuck way too often. But yeah, I appreciate the help.

psycopathicteen: SMW is by far the easiest game to hack, and SMW hacking is definitely easier than homebrew and the like. And...I'm not sure I understand some of your terminology. Height- and length-defined metasprites?

psycopathicteen
Posts: 2915
Joined: Wed May 19, 2010 6:12 pm

Post by psycopathicteen » Mon Sep 06, 2010 7:51 pm

I'm programming a game that will be made for the intent of easy hacking.

psycopathicteen
Posts: 2915
Joined: Wed May 19, 2010 6:12 pm

Post by psycopathicteen » Tue Sep 07, 2010 7:13 am

For height and legnth defined metasprites I mean using a parameter that say how many hardware sprites tall and wide the game object is. I used to have it where the offset of every sprite was stored seperately in a lookup table, but making a look up table for every sprite takes too long to do.

tepples
Posts: 21874
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples » Tue Sep 07, 2010 8:02 am

Cut scenes in the story mode of Concentration Room 0.02 use a compromise between specifying a sprite cel as a rectangular block of hardware sprites and specifying each sprite individually. Each sprite cel is divided into horizontal or vertical strips, each of which has a left, top, starting tile number, direction, length in tiles, and attributes. Direction can be right or down, attributes relate to flipping and coloring, and both may be multiplexed onto unused bits of the length. For drawing to the right, x increases by 8 or -8 depending on flip, y increases by 0, and tile number increases by 1. For drawing down, x increases by 0, y increases by 8, and tile number increases by 16.

gilligan
Posts: 35
Joined: Tue Jan 04, 2005 7:31 am
Contact:

Post by gilligan » Wed Sep 08, 2010 3:29 am

You can have a look at my stuff at: http://www.github.com/gilligan/snesdev

It contains some simple examples that might or might not be useful
to look at as a starting point :-) Don't expect anything awesome it
is still a bit of a mess and hopefully i'll find the time and motivation
to rework and extend it sometime soon.

I also need to add some credits. Things like the ca65 linking is based on the stuff ekid has done, and there are other things like some sprite I reused from (iirc) the neviksti snes starterkit thingy. That one might also be worthwhile to check out.

Comments or contributions are always welcome by the way.
gilligan

psycopathicteen
Posts: 2915
Joined: Wed May 19, 2010 6:12 pm

Post by psycopathicteen » Thu Sep 09, 2010 4:10 pm

Oh yeah, I forgot about this cool dual-layered rotation trick using Mode-2.

http://nesdev.com/bbs/viewtopic.php?t=6679

It gets explained in here.

imamelia
Posts: 7
Joined: Wed Sep 01, 2010 12:17 am

Post by imamelia » Sun Oct 17, 2010 10:25 pm

Hm...I'm thinking maybe I should have made this thread over the summer or something, some time when I'd have more time...

Well, I've already run into problems. This is my source code so far:

Code: Select all

;header
lorom

;org $008000
;fillbyte $FF : fill $8000

org $008000

ResetSNES:

SEI			; disable IRQ
REP #$39			; clear carry and set 16-bit A
XCE			; clear emulation mode flag
LDA.w #$0000		; set the direct page to $0000
TCD			;
JSR InitRAM		;
LDA.w #$0FFF		; set the stack to $0FFF
TCS			;
LDA.w #$008F		; force blank on, maximum brightness,
STA $2100		;
JSR Clear2100s		; clear registers $21xx
;JSR Clear4000s		; clear registers $40xx
JSR Clear4200s		; clear registers $42xx
SEP #$20			; set 8-bit A
JSR ClearVRAM		; clear out the VRAM
JSR ClearPalette		; clear out the palette (reset all colors to 0000)
JSR InitVals		; initialize some registers to nonzero values
SEP #$10			; set 8-bit XY
JSR SetRAMRoutines		;
JSR UploadSPCEngine	;
JSR UploadSamples		;
JSR SetUpHDMA		;

CLI			;

STZ $2121		;
LDA #$EF			;
LDX #$3F			;
STA $2122		;
STX $2122		;
LDA #$0F			;
STA $2100		;

WAI			;
BRA $FD			;

;RTI			;

Clear2100s:

STZ $2101
STZ $2106
STZ $2108
STZ $210A
STZ $210C
STZ $210D
STZ $210D
STZ $210F
STZ $210F
STZ $2111
STZ $2111
STZ $2113
STZ $2113
STZ $2116
STZ $211A
STZ $2115
STZ $211C
STZ $211C
STZ $211E
STZ $211E
STZ $2120
STZ $2120
STZ $2123
STZ $2125
STZ $2127
STZ $2129
STZ $212B
STZ $212D
STZ $212F
STZ $2131
STZ $2133
RTS

Clear4200s:

STZ $4200
STZ $4202
STZ $4204
STZ $4206
STZ $4208
STZ $420A
STZ $420C
RTS

InitVals:

LDA #$03
STA $2101
LDA #$80
STA $2115
LDA #$01
STA $211B
LDA #$30
STA $2130
LDA #$E0
STA $2132
LDA #$FF
STA $4201
LDA #$01
STA $420D
RTS

ClearVRAM:

LDA #$80		;
STA $2115	;
LDX #$1809	;
STX $4300	;
LDX.w #$0000	;
STX $2116	;
STX $00		;
STX $4302	;
STZ $4304	;
LDX #$FFFF	;
STX $4305	;
LDA #$01		;
STA $420B	;
STZ $2119	;

STZ $2102	;
STZ $2103	;
LDX.w #$007F	;
LDA #$F0		;
.Loop00x1	;
STA $2104	;
STA $2104	;
STZ $2104	;
STZ $2104	;
DEX		;
BPL .Loop00x1	;
LDX.w #$001F	;
.Loop00x2	;
STZ $2104	;
DEX		;
BPL .Loop00x2	;
RTS		;

ClearPalette:

STZ $2121	;
LDX.w #$00FF	;
.Loop00x3	;
STZ $2122	;
STZ $2122	;
DEX		;
BPL .Loop00x3	;
RTS		;

InitRAM:

PHP		;
SEP #$20		;
STZ $2181	;
STZ $2182	;
STZ $2183	;
LDX #$8008	;
STX $4300	;
LDX #$8005	; $008005
STX $4302	;
STZ $4304	; $008005 is always 00, so use that as our WRAM fill byte
LDX.w #$0000	;
STX $4305	;
LDA #$01		;
STA $420B	;
LDA #$01		;
STA $420B	;
PLP		;
RTS		;

SetRAMRoutines:
RTS

UploadSPCEngine:
RTS

UploadSamples:
RTS

SetUpHDMA:
RTS

org $00FFDF	;
db $60		; RTS
dw $FFFF,$FFFF	;
dw $FFDF		; COP
dw $FFDF		; BRK
dw $FFDF		; ABORT
dw $FFDF		; NMI
dw $8000		; RESET
dw $FFDF		; IRQ
Many of the routines are from tutorials and stuff. But I was just trying to reset the SNES and show a green color on the screen (using an example code I found), and absolutely nothing happens when I load the ROM. I can't even set breakpoints to step through the code, apparently.

smkd
Posts: 101
Joined: Sun Apr 22, 2007 6:07 am

Post by smkd » Sun Oct 17, 2010 11:38 pm

Had a quick look and noticed a few things. Here's a list and source slightly modified to get a green screen like intended.

-the vectors are incorrectly set. The 1.51 Snes9x debugger has a "Vector Info" button that shows these, not sure about bsnes. The reset vector was being read as $0000 so it would not start at all.

-don't do any 16bit REP stuff before getting out of emulation mode. Caused the LDA #$0000 to be treated as a BRK in snes9x debugger since it kept A in 8bit mode despite your REP:

Code: Select all

REP #$39         ; clear carry and set 16-bit A
XCE         ; clear emulation mode flag
LDA.w #$0000      ; set the direct page to $0000 
-don't JSR or anything that requries stack space before setting up the stack with TCS

Code: Select all

JSR InitRAM      ;
LDA.w #$0FFF      ; set the stack to $0FFF
TCS
-InitRAM trashed the stack as part of the RAM clear. There was a return address and the contents pushed by PHP trashed with it so it crashed after the RTS. It's been altered to clear all RAM except the $7E0F00-$7E0FFF region which is assumed to be stack space.

-Pointing interrupts to RTS will crash when returning. It must be an RTI instead.

-ClearVRAM looks odd but it wouldn't crash anything. You can point $4302-$4304 to a dedicated zero byte in ROM as I have used in InitRAM instead of storing a zero to RAM and using that. The InitRAM original approach also used a hardcoded address that would not necessarily be zero if the code changed (like it just did). A dedicated zero byte with its own label is more reliable.

Without going into any of the other quirks, those changes got your green screen in snes9x and bsnes.

Code: Select all

lorom

;org $008000
;fillbyte $FF : fill $8000

org $008000

ResetSNES:

SEI         ; disable IRQ
CLC
XCE         ; clear emulation mode flag
REP #$30    ;*do not try to load 16bit values in emulation mode
LDA.w #$0000      ; set the direct page to $0000
TCD         ;
LDA.w #$0FFF      ; set the stack to $0FFF
TCS             ;*and do this BEFORE trying to call subroutines
JSR InitRAM      ;    ;
LDA.w #$008F      ; force blank on, maximum brightness,
STA $2100      ;
JSR Clear2100s      ; clear registers $21xx
;JSR Clear4000s      ; clear registers $40xx
JSR Clear4200s      ; clear registers $42xx
SEP #$20         ; set 8-bit A
JSR ClearVRAM      ; clear out the VRAM
JSR ClearPalette      ; clear out the palette (reset all colors to 0000)
JSR InitVals      ; initialize some registers to nonzero values
SEP #$10         ; set 8-bit XY
JSR SetRAMRoutines      ;
JSR UploadSPCEngine   ;
JSR UploadSamples      ;
JSR SetUpHDMA      ;

CLI         ;

STZ $2121      ;
LDA #$EF         ;
LDX #$3F         ;
STA $2122      ;
STX $2122      ;
LDA #$0F         ;
STA $2100      ;

WAI         ;
BRA $FD         ;

;RTI         ;

Clear2100s:

STZ $2101
STZ $2106
STZ $2108
STZ $210A
STZ $210C
STZ $210D
STZ $210D
STZ $210F
STZ $210F
STZ $2111
STZ $2111
STZ $2113
STZ $2113
STZ $2116
STZ $211A
STZ $2115
STZ $211C
STZ $211C
STZ $211E
STZ $211E
STZ $2120
STZ $2120
STZ $2123
STZ $2125
STZ $2127
STZ $2129
STZ $212B
STZ $212D
STZ $212F
STZ $2131
STZ $2133
RTS

Clear4200s:

STZ $4200
STZ $4202
STZ $4204
STZ $4206
STZ $4208
STZ $420A
STZ $420C
RTS

InitVals:

LDA #$03
STA $2101
LDA #$80
STA $2115
LDA #$01
STA $211B
LDA #$30
STA $2130
LDA #$E0
STA $2132
LDA #$FF
STA $4201
LDA #$01
STA $420D
RTS

ClearVRAM:

LDA #$80      ;
STA $2115   ;
LDX #$1809   ;
STX $4300   ;
LDX.w #$0000   ;
STX $2116   ;
STX $00      ;
STX $4302   ;
STZ $4304   ;
LDX #$FFFF   ;
STX $4305   ;
LDA #$01      ;
STA $420B   ;
STZ $2119   ;

STZ $2102   ;
STZ $2103   ;
LDX.w #$007F   ;
LDA #$F0      ;
.Loop00x1   ;
STA $2104   ;
STA $2104   ;
STZ $2104   ;
STZ $2104   ;
DEX      ;
BPL .Loop00x1   ;
LDX.w #$001F   ;
.Loop00x2   ;
STZ $2104   ;
DEX      ;
BPL .Loop00x2   ;
RTS      ;

ClearPalette:

STZ $2121   ;
LDX.w #$00FF   ;
.Loop00x3   ;
STZ $2122   ;
STZ $2122   ;
DEX      ;
BPL .Loop00x3   ;
RTS      ;

InitRAM:
PHP      ;
SEP #$20      ;
STZ $2181   ;
STZ $2182   ;
STZ $2183   ;
LDX #$8008   ;
STX $4300   ;
STZ $4304       ;we're only ever in bank 00
LDX #.zeroByte   ;*dedicated zero byte
STX $4302   ;
LDX.w #$0F00   ;clear 7E0000-7E0EFF
STX $4305   ;
LDA #$01
STA $420B
LDX #$1000    ;clear 7E1000-7EFFFF
STX $2181
LDX #$F000
STX $4305
LDA #$01
STA $420B
STA $2183    ;bank $7F now
STA $420B    ;*$4305 already has $0000 loaded into after a finished DMA so no need to set it here
PLP     ;
RTS      ;
.zeroByte    ;*dedicated zero byte
    db 0

SetRAMRoutines:
RTS

UploadSPCEngine:
RTS

UploadSamples:
RTS

SetUpHDMA:
RTS

;interrupts all go here, nothing happening there yet

EmptyHandler:
RTI

;native:
org $00FFE4   ;
dw EmptyHandler    ;COP
dw EmptyHandler ;BRK
dw 0
dw EmptyHandler    ;NMI
dw 0
dw EmptyHandler    ;IRQ

;emulation
org $FFFA
dw EmptyHandler    ;NMI
dw ResetSNES    ;*Reset
dw EmptyHandler    ;IRQ/BRK

User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg » Mon Oct 18, 2010 1:11 am

I recommend using an assembler that keeps track of the size of A and X&Y so you don't have to remember to do LDA.W each time. Forget it and you'll get bugs that you might not find for a while. Once you have such an assembler (maybe this one supports this), I suggest keeping A 8 bits and X&Y 16 bits most of the time. You often need to do 8-bit manipulation, so having A 8 bits makes this easy. Sometimes you need to do simple 16-bit operations, and X&Y serve for this. Rarely you might need to switch A to 16 bits, but switch it back afterwards. This convention has worked well for me and avoided the problems with having to deal with different register sizes throughout code.

psycopathicteen
Posts: 2915
Joined: Wed May 19, 2010 6:12 pm

Post by psycopathicteen » Tue Oct 19, 2010 7:50 am

I wish I used labels/defines when I wrote my "project SNES" engine. It defeats the purpose because it was supposed to be an easy-to-pick-up engine, and I once again didn't make it readable enough. Now I have to go back and fix it, and this will take forever to do.

It's a good thing I'm labeling my software rotation code. I think of sprite rotation being the pinacle of 2D graphical effects, and it will be awsome seeing it in everybody's homebrew games.

Post Reply