I'm having trouble finding good source material for the SNES to start learning from. I found 1 Hello World on github (in German). But, there's no nerdy nights equivalent for the SNES.
I was thinking about using a debugger and going step by step through an actual game, to see how it initializes things and sets everything up. Does anyone have any suggestions for a simple game I can start looking at, or should I just start with SMW since it's so well documented? Did anyone make a Pac-man or Galaga port to the SNES that I can look at (examples of simple games).
Oh, I see that Frogger, Space Invaders, and Ms. Pacman were. Space invaders might be the easier of them to figure out.
Superfamicom.org is your friend:
http://wiki.superfamicom.org/snes/show/HomePageYou could try looking at bazz's tutorials just like I did, but I'm sure you already know most of that stuff, and they're using WLA... I started off fiddling with the Walker demo in "Neviksti's Starter Kit" under this:
http://wiki.superfamicom.org/snes/show/ ... nvironment
I've got a
walker demo for Super NES in ca65 if you're interested.
Thanks guys.
I don't know if I'm going to make any SNES homebrews, but I've had a few people ask me if I can mod SNES games, and I'd really like to learn it, since SNES was the system I played through high school.
Dumb question... what's the difference between HiROM and LoROM?
In LoROM (mode $20), CPU A15 isn't connected to the ROM. In HiROM (mode $21), it is. This means in LoROM, data occupies the upper half of each 64 KiB bank, while in HiROM, ROM data occupies the whole bank. LoROM is intended to be accessed through $808000-$80FFFF, $818000-$81FFFF, $828000-$82FFFF, etc., while HiROM just starts at $C00000 and goes up. The reason for LoROM's existence is related to the mirroring of the first 8 KiB of RAM and MMIO registers throughout banks $00-$3F and $80-$BF so that you don't always have to use (slower) long addressing modes to reach MMIO. However, the second half of each bank of HiROM is also mirrored down into $80-$BF, letting you do MMIO with 2-byte addresses from pseudo-LoROM routines stored there.
View more definitions
Just so I understand...
In either mode, LoROM or HiROM, can I access all banks?
Edit. Oh wait, there are 2 different types of cartridges... One mapped with LoROM and one mapped with HiROM. Do I have that right? And so, its not like switching from Native mode to Emulator mode, or something like that.
dougeff wrote:
Just so I understand...
In either mode, LoROM or HiROM, can I access all banks?
Edit. Oh wait, there are 2 different types of cartridges... One mapped with LoROM and one mapped with HiROM. Do I have that right? And so, its not like switching from Native mode to Emulator mode, or something like that.
Yeah, it's two types of cartridges that are physically wired differently--a bit like horizontal/vertical CIRAM mirroring on the NES.
There are actually a lot more than two cartridge types, with subtle differences involving which address ranges are mirrored in cartridges with SRAM and/or with multiple physical ROM chips, but you really don't have to worry about them unless you're an emulator developer.
Ive read every document on SNES that I could find. I have a few questions...just so I know I have it right.
1. The SNES has a VRAM that is divided into 3 parts...Color palette, OAM (sprite attributes), and tilemap...each accessible though different registers...
2121/2122 for palette, 2102-4 OAM, 2116-9 tilemap. Do I have that right?
2. How do I write tile data then (CHR)?
3. Do you usually write to the VRAM with a DMA?
4. Do you have to write to VRAM during V-blank?
5. In mode 1, there are 3 BG layers? If an upper one is mostly color 0, does that work as a mostly transparent layer?
Edit...
6. I'm also slightly confused with joypad reads. There seems to be 2 ways to read the joypads (auto and manual) with a warning somewhere about getting incorrect reads if done at the wrong time. Is there a 'standard' way of doing this?
dougeff wrote:
1. The SNES has a VRAM that is divided into 3 parts...Color palette, OAM (sprite attributes), and tilemap...each accessible though different registers...
Yes, much as with the NES, except the palette doesn't overlay the last 256 words of VRAM addresses anymore.
Quote:
2. How do I write tile data then (CHR)?
It should be familiar if you've ever used CHR RAM on the NES: write the address, then write the data. Tiles and tile map both go in the main 32 Kword (64 KiB) VRAM.
Quote:
3. Do you usually write to the VRAM with a DMA?
Yes. "Blast Processing" is one advantage the Genesis and Super NES have over the third-gen systems.
Quote:
4. Do you have to write to VRAM during V-blank?
Yes, just as on the NES. Unlike on the Genesis, there's no VRAM write FIFO. Or if you're willing to do a little letterboxing, you can also write during forced blank. This is a lot easier to pull off on the Super NES than on the NES.
Quote:
5. In mode 1, there are 3 BG layers? If an upper one is mostly color 0, does that work as a mostly transparent layer?
Correct.
Thanks. I was editing (adding another question) while you were typing. Any thoughts on button reads?
And...
7. Do sprites use the same tileset that BGs do in the same area of the VRAM?
The base address for sprite tiles, each background's tiles, and each background's tile map can be set independently. A 16-color background can address 32K of tiles, but the sprite system can address only 16K at once. You might be able to get away with a layout like this in mode 1:
$0000-$3FFF (32K): 1024 tiles for BG1 and BG2
$4000-$5FFF (16K): 512 sprite tiles
$6000-$67FF (4K): BG1 map
$6800-$6FFF (4K): BG2 map
$7000-$77FF (4K): BG3 map
$6000-$7FFF ($7800-$7FFF used): 256 HUD tiles for BG3
These are word addresses, where $0000 refers to 16 bits, $0001 refers to the next 16 bits, etc.
dougeff wrote:
Ive read every document on SNES that I could find. I have a few questions...just so I know I have it right.
1. The SNES has a VRAM that is divided into 3 parts...Color palette, OAM (sprite attributes), and tilemap...each accessible though different registers...
2121/2122 for palette, 2102-4 OAM, 2116-9 tilemap. Do I have that right?
2. How do I write tile data then (CHR)?
3. Do you usually write to the VRAM with a DMA?
4. Do you have to write to VRAM during V-blank?
5. In mode 1, there are 3 BG layers? If an upper one is mostly color 0, does that work as a mostly transparent layer?
1. Mostly correct, but CGRAM (the palette) and OAM aren't normally referred to as VRAM.
2. VRAM contains both the name tables (tilemaps) and the pattern tables (CHR data). Unlike the NES, which has the name tables and pattern tables at fixed addresses in the PPU address space, the SNES has registers to specify the addresses where the name table and the pattern table for each layer are located (including the pattern table for sprites).
3. Yes, uploading data to the PPU is almost always done via DMA. Even writing to the scroll registers may be done via DMA.
4. Yes. VRAM can only be accessed during VBlank or forced blank. Unlike the NES, accessing VRAM outside VBlank simply fails (writes go nowhere, reads return 0) with no side effects on the display. CGRAM can be accessed normally during either VBlank or HBlank; some games write to CGRAM during HBlank to produce a color gradient. You can "sort of" access OAM outside VBlank but what you can do with it is very limited; Uniracers is the only game that intentionally does so.
5. Typically the 2bpp layer (BG3) is used as the score/status display and is therefore mostly blank (transparent) tiles. Or it may be multiplexed as both a score/status display and a far BG, using a raster effect to change its scroll position and priority partway down the screen (see e.g. Super Castlevania) Note that doing raster effects on the SNES is much, much easier than on the NES. Both a beam-position IRQ (a real one, not fake like MMC3) and beam-triggered DMA (HDMA) are built into the base system, and there's no voodoo needed for midscreen scroll changes, you just write the new vertical and horizontal positions exactly the same way you would during VBlank.
Quote:
Edit...
6. I'm also slightly confused with joypad reads. There seems to be 2 ways to read the joypads (auto and manual) with a warning somewhere about getting incorrect reads if done at the wrong time. Is there a 'standard' way of doing this?
The standard way to read normal SNES controllers is using the auto read. In VBlank, after doing all the OAM/VRAM/CGRAM uploads you're going to do, wait for bit 0 of $4212 to go to 0 and then read $4218-$421B. Manual reading is only needed for special controllers: mouse, multitap, light guns, etc.
tepples wrote:
The base address for sprite tiles, each background's tiles, and each background's tile map can be set independently. A 16-color background can address 32K of tiles, but the sprite system can address only 16K at once. You might be able to get away with a layout like this in mode 1:
$0000-$3FFF (32K): 1024 tiles for BG1 and BG2
$4000-$5FFF (16K): 512 sprite tiles
$6000-$67FF (4K): BG1 map
$6800-$6FFF (4K): BG2 map
$7000-$77FF (4K): BG3 map
$6000-$7FFF ($7800-$7FFF used): 256 HUD tiles for BG3
These are word addresses, where $0000 refers to 16 bits, $0001 refers to the next 16 bits, etc.
BGxxNBA have granularity of $1000 words, so I don't see the need to locate the BG3 tiles in such a weird way...
AWJ wrote:
BGxxNBA have granularity of $1000 words, so I don't see the need to locate the BG3 tiles in such a weird way...
Also possible:
$7000-$77FF (4K): 256 HUD tiles for BG3
$7800-$7FFF (4K): BG3 map
Or
$7000-$7BFF (6K): 384 HUD tiles for BG3
$7C00-$7FFF (2K): BG3 map (not scrolling)
You can, of course, overlap OBJ tables and BG tile data, and use literally the same tiles for both. But only for 4bpp BG layers; otherwise you get a format mismatch. And of course both sprite tables combined would only cover half of the valid BG data range.
I need some help. I've been trying to write a "Hello World" SNES program, but so far it's been a total failure. I've modified it to just fill all BG tilemaps with tiles and display 2 sprites (and turn the background green)...
Except I'm getting nothing. Nothing but a blank green screen.
Here's the source files and snes file...I just want it to show ANYTHING at all on the screen. Can anyone explain to me what I'm doing wrong? I want to understand this, but the documents for SNES are hard to understand...especially VRAM writes / registers.
http://dl.dropboxusercontent.com/s/bsl0 ... /Hello.zipEDIT: DON'T USE THIS CODE. BROKEN. LEFT HERE FOR REFERENCE.
Compiles with ca65.
Solved...
Apparently I needed to add this at the end...
Code:
lda #$1f
sta $212C ;enable main screen!!!
It only took me about 3 hours to figure out that
There's my lovely little sprites. Yay!
I'd say I have success. The above link has been updated, if anyone wants to see source code for a working "Hello World" for the SNES.
I got a Super Everdrive yesterday, tried this file, and none of the sprites appear on screen. (Sprites are letters, BG is numbers). Any ideas?
BTW, my loop is this...
Forever:
Jmp Forever
And my NMI/IRQ is...
Rti
Am I supposed to do something each frame to get sprites to work? I know you have to continually send sprite data on NES. (Or else they all jump to the corner of the screen)
You should use bsnes(-plus) for testing, rather than Snes9X. It's more accurate, so if it works on there it'll be more likely to work on hardware.
Three guesses (in order from most to least likely):
You're writing data to VRAM during not-vblank
OR
You're relying on uninitialized RAM somehow
OR
Your header data is invalid somehow, causing the Super Everdrive to map it improperly
I did test with higan/bsnes accuracy. It looks fine.
On hardware, Bg is fine. No sprites.
Tried pushing sprites every frame. No difference.
OAM persists on SNES. You don't need to resend it.
Also, if you're actually using an interrupt, you need to clear the IRQ flag by reading $4211, or it will keep firing ad infinitum. According to fullsnes you don't actually have to read $4210 in an NMI, but it's good practice anyway (and I'm not sure I'm impressed by his excuse).
Do games work properly on your SNES?
93143 wrote:
According to fullsnes you don't actually have to read $4210 in an NMI, but it's good practice anyway (and I'm not sure I'm impressed by his excuse).
I'd say that reading $4210 on Super NES is approximately as required as reading $2002 on NES, but at least $2002 clears the PPU's first/second write latch.
93143 wrote:
and I'm not sure I'm impressed by his excuse
...that sounded really rude, didn't it?
His explanation was that the NMI flag is cleared at the end of VBlank, so unless you're disabling and re-enabling NMI, you shouldn't have to clear it yourself. I'm pretty sure nocash knows more about the SNES than I do, but it's not obvious to me what happens if your NMI routine ends before the flag is cleared.
Quote:
Do games work properly on your SNES?
Yes.
No problems with games, nor with the Everdrive.
It's a code problem. I just don't know enough SNES programming to understand, or fix.
Mind posting your code so that we can take a look?
Are you writing correctly to the second OAM table? It's been a while since my SNES days, but I do seem to recall having a similar problem and it was caused by (IIRC) not correctly writing to the second OAM table that contains the X coordinates MSB and the sprite size.
Also, the way OAM works on the SNES seems weird to me. IIRC, you have the set the sprite number multiplied by either 2 or 4 when you write the OAM address low.
Quote:
Mind posting your code so that we can take a look?
It's the Dropbox link above...the only thing I've changed from that is the Vectors.
Quote:
Writing to the second OAM table
I don't think so.
CORRECTION - I think I'm filling it with zeros.
zkip wrote:
Also, the way OAM works on the SNES seems weird to me. IIRC, you have the set the sprite number multiplied by either 2 or 4 when you write the OAM address low.
Not particularly weird considering that the size of each OAM entry is 4 bytes.
Quote:
Not particularly weird considering that the size of each OAM entry is 4 bytes.
Exactly, so why multiply the address by 2? (I'm recalling now that it was actually 2 because that's what made it seem weird to me.)
By the way, I actually have no right to try to help here. I'm probably confusing you more. It's been 5+ years since I've done anything with the SNES.
I'm just frustrated. I just got my running shoes (everdrive) in the mail, and want to go for a jog, and then i spend 4 hours trying to tie my shoes (and failing).
You seem to be writing sprites in a straight forward way. Maybe
try DMAing the sprites from a copy in RAM? Not sure if those "tutorials" have been depreciated yet or not though.
I got it to work.
I wrote to the low table, but then no follow up to the high table, thus the low table was never updated, my sprites didn't appear.
Ok, I feel better.
Edit, I think I misunderstood the wiki above, but somehow, rewriting the entire OAM (low and high) fixed it, and sprites are showing. Perhaps leaving the OAM address set mid-way screws things up.
zkip wrote:
Quote:
Not particularly weird considering that the size of each OAM entry is 4 bytes.
Exactly, so why multiply the address by 2? (I'm recalling now that it was actually 2 because that's what made it seem weird to me.)
By the way, I actually have no right to try to help here. I'm probably confusing you more. It's been 5+ years since I've done anything with the SNES.
Yet you couldn't resist the urge to spread disinformation in the very same post?
Of course you don't multiply by 2 to index into an array of data structures of size 4.
2 what? 4 what?
To clarify things, I applied
dimensional analysis. I searched
superfamicom.org's page about MMIO ports for "word address", and it turns out VRAM, OAM, and CGRAM are all addressed in 16-bit units. Such address registers behave as if they multiply the address by 2 bytes per word. Thus accessing data structures of size 4 bytes per element requires multiplying the index by 2 words per element, not 4 bytes per element.
But in practice, it's more common to write to OAM using DMA from a display list in a memory that's byte-addressed, namely WRAM. For this, you do need 4 bytes per element.
Quote:
Yet you couldn't resist the urge to spread disinformation in the very same post?
At least I tried to help?
No need to be snarky.
BTW, thanks tepples for clearing that up.
dougeff wrote:
I got it to work!
Quote from the superfamicom wiki
Quote:
the low table of OAM is not affected until the high byte of a word is written
I wrote to the low table, but then no follow up to the high table, thus the low table was never updated, my sprites didn't appear.
Ok, I feel better.
Edit, I think I misunderstood the wiki above, but somehow, rewriting the entire OAM (low and high) fixed it, and sprites are showing. Perhaps leaving the OAM address set mid-way screws things up.
Think of the high table as a separate chip that is only accessed with addresses 512..543. Only the lower table has a latch that buffers writes.
See anomie's regs.txt (e.g. on RHDN) for details.
I was still having tons of problems, bugs, making me very angry... I think I fixed it... my bad init code says this...
sep #$20 ;a 8
rep #$10 ;i 16
...
lda #$00
tcd
But, TCD transfers low AND high byte of A+B, regardless of processor status, and the value of A is not know at startup, so I was storing a random value for the high byte of the Direct Page Register.
correct init code should be...
rep #$30 ;a 16 i 16
lda #$0000
tcd
Ok, hopefully, I can get this stupid first test program up and running soon.
Well, or
sep #$20
lda #0
xba
lda #0
tcd
Also, the 65816 datasheet says D is set to 0 on reset (although I suppose it's possible that this is not true for the 5a22?)
I assume this is still running on the Everdrive, in which case that's probably not a safe assumption.
Yes, I'm running on an Everdrive.
Here's the code that IS working on the Everdrive. Slight changes, the background auto-scrolls left (during NMI, let's me know that NMI is firing correctly). And, Controller Reads, Up/Down/Left/Right moves one of the sprites (outside of NMI, let's me know program is running outside NMI correctly).
http://dl.dropboxusercontent.com/s/n93a ... ello11.zipImprovement still needed, pushing unused sprites offscreen. You can see them in the top left corner. I can't seem to find any documentation on this. Perhaps a Y value of $ff would do it?
Hey, should I also do this on INIT?
lda #00
pha
plb ; set the data bank to 0
EDIT: link updated to push unused sprites to Y = $f0.
zkip wrote:
At least I tried to help?
No need to be snarky..
Yeah, sorry about lashing out a bit there. Especially since you stating "multiplying by either 4 or 2" is technically exactly true depending if you want the word or byte offset.
(Then, of course, not having an OAM shadow buffer in RAM and DMA it during vblank is rather bonkers, so it didn't even cross my mind that you might want to use the word offset.)
Sometimes I just get a bit disillusioned with how SNES homebrew never seems to be able to get out of the ghetto...
Quote:
pushing unused sprites offscreen
You can use the 9th bit for the X location (located in the second OAM table) of the sprite to move it off-screen. Actually, I'm pretty sure that this is the exact purpose of having this bit there anyway as I see no other reason for it.
Quote:
Sometimes I just get a bit disillusioned with how SNES homebrew never seems to be able to get out of the ghetto...
I agree. There's some sort of jump-start that NESDEV got that SNES didn't.
zkip wrote:
Actually, I'm pretty sure that this is the exact purpose of having this bit there anyway as I see no other reason for it.
It's necessary for moving sprites partially off the left side of the screen.
I believe you can also set the Y coordinate to 240 if you don't want to have to touch the high table, as long as your sprites aren't larger than 16x16 (otherwise they'll wrap around and be partially visible at the top of the screen).
You can't smoothly scroll sprites in from the left side of the screen, with the sprite partially onscreen, without the hioam.
As for dealing with hioam, I always just stored the full x-coordinates and size bits on a separate table, and then afterwards, jump to a routine that builds the hioam all at once.
zkip wrote:
Quote:
pushing unused sprites offscreen
You can use the 9th bit for the X location (located in the second OAM table) of the sprite to move it off-screen. Actually, I'm pretty sure that this is the exact purpose of having this bit there anyway as I see no other reason for it.
Quote:
Sometimes I just get a bit disillusioned with how SNES homebrew never seems to be able to get out of the ghetto...
I agree. There's some sort of jump-start that NESDEV got that SNES didn't.
One day I am going to make a tutorial on how to make a giant screen filling robot with rotating limbs and body, once I actually make a demo of one. If that doesn't make people want to do SNES homebrew then I don't know what will. The nice thing about rotating sprites is that if you run out of CPU speed and RAM, you can pre-render everything else in ROM.
Revenant wrote:
I believe you can also set the Y coordinate to 240 if you don't want to have to touch the high table, as long as your sprites aren't larger than 16x16 (otherwise they'll wrap around and be partially visible at the top of the screen).
Thanks. I think this would be the easiest method.