It is currently Wed Sep 18, 2019 2:41 pm

All times are UTC - 7 hours



Forum rules





Post new topic Reply to topic  [ 28 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Mon Jul 29, 2019 11:16 am 
Offline
User avatar

Joined: Fri Mar 16, 2018 1:52 pm
Posts: 98
Location: Finland
I was thinking of trying SNES programming, but there are a few things that I need to ask about before I can start.

The first thing is to understand how the SNES uses the available memory. As far as I know, RAM and registers are at $xx:0000 - $xx:7FFF and ROM is at $xx:8000 - $xx:FFFF. xx is the value at Program Bank or Data Bank register depending on whether its accessed by read/write instruction or instruction fetch. Do reads/writes at $0000 - $7FFF care what value xx is?

Now, PPU memory is a bit more of a mystery to me. How do you assign pattern tables and how many tiles can they hold at once? Can parts of the pattern table be swapped or are you limited to certain minimum sizes you can swap at once? Or can you swap individual tiles kinda like CHR RAM on some NES mappers? What about nametables and attributes?


Top
 Profile  
 
PostPosted: Mon Jul 29, 2019 11:36 am 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 8559
Location: Seattle
SusiKette wrote:
The first thing is to understand how the SNES uses the available memory.
There are multiple different ways that cartridges work. What you described is "Mode 20h", mostly, or "LoROM".

Divide the 24-bit address of the SNES's CPU into three eight-bit quantities. In order, call those the "bank", "page", and ... nothing.

The SNES itself only imposes a few limits:
  • 8K of RAM can be accessed in banks $00-$3F, $7E, and $80-$BF, across pages $00-$1F.
  • 128K of RAM can be accessed in banks $7E and $7F, across all pages, not redundant.
  • registers to configure how everything operates can be accessed in banks $00-$3F and $80-$BF, in pages $21 and $40-$43.

But "bank" is misleading: the SNES's CPU provides the ability to natively specify the full 24-bit address without using bankswitching.

The SNES hardware makes specific memory layouts easier. It provides a specific signal on the connection to the cartridge that lets the cart know when ("bank" is $40-$7D or $C0-$FF) or ("bank" is $00-$3F or $80-$BF and "page" is $80-$FF).

Quote:
How do you assign pattern tables and how many tiles can they hold at once? Can parts of the pattern table be swapped or are you limited to certain minimum sizes you can swap at once? Or can you swap individual tiles kinda like CHR RAM on some NES mappers? What about nametables and attributes?
In the SNES, 64KB of RAM is available to hold everything to be drawn. Unlike the NES, this cannot be changed by the cartridge. Also unlike the NES, there's a wide variety of ways to interpret the data. There is no attribute table; nametable entries are always 16 bits wide. Up to four background layers plus a layer of sprites can be drawn, each from their own location in memory. Each background layer has its own nametable, each nametable can be any of the four combinations of 32 or 64 tiles wide and tall; each nametable entry can represent an 8x8 (or 16x8 in specific cases) or a 16x16 pixel region.

I'd suggest using some SNES emulator with a debugger—NO$SNS, bsnes-plus, or Mesen-S—and looking at what's going on.


Top
 Profile  
 
PostPosted: Mon Jul 29, 2019 3:12 pm 
Offline
User avatar

Joined: Fri Mar 16, 2018 1:52 pm
Posts: 98
Location: Finland
lidnariq wrote:
In the SNES, 64KB of RAM is available to hold everything to be drawn. Unlike the NES, this cannot be changed by the cartridge. Also unlike the NES, there's a wide variety of ways to interpret the data. There is no attribute table; nametable entries are always 16 bits wide. Up to four background layers plus a layer of sprites can be drawn, each from their own location in memory. Each background layer has its own nametable, each nametable can be any of the four combinations of 32 or 64 tiles wide and tall; each nametable entry can represent an 8x8 (or 16x8 in specific cases) or a 16x16 pixel region.


So in other words, the programmer defines where each data is located in VRAM? Still I don't know how you define sprite graphics location, or is it fixed?


Top
 Profile  
 
PostPosted: Mon Jul 29, 2019 3:28 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 2563
Location: DIGDUG
Register 2101, Name Base Select is the last 3 bits... actually the last 2 bits, the 3rd one is unused.

So sprite graphics can be at $0000, $2000, $4000 or $6000 in the VRAM.

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
PostPosted: Mon Jul 29, 2019 3:32 pm 
Offline

Joined: Tue May 28, 2013 5:49 am
Posts: 1187
Location: Hokkaido, Japan
Quote:
So in other words, the programmer defines where each data is located in VRAM? Still I don't know how you define sprite graphics location
Exactly! You set the base address in VRAM for each "SC" (tilemap nametable) for each background layer, the "BG CHR name" (pattern table for background characters) and the "OBJ CHR name" (pattern table for sprites) using hardware registers. For example the SC base addresses are set by writing the addresses to registers $2107-$210A. Depending what modes, formats and sizes you use, you have to plan and set up VRAM accordingly.

The Color Generator (palette) and OBJ attributes (sprite attributes) however have their own fixed memory and are not set in VRAM. The palette is set into CGRAM and sprite attributes are in OAM like for NES.


Top
 Profile  
 
PostPosted: Mon Jul 29, 2019 6:10 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 4208
Location: A world gone mad
In short: yes, you choose where things in PPU RAM end up. You get to manage/define the 64KByte of space yourself.

Be aware, however:

1. There are alignment requirements for each "type" of data:

a) Background nametable (officially called "BG-SC" or "SC" data) base address is 2KByte / 1KWord aligned; see MMIO registers $2107-210A
b) Background CHR (officially called "BG character data") base address is 8KByte / 4KWord aligned; see MMIO registers $210B-210C
c) Sprites/OAM are more complicated; there is an 16KByte / 8KWord alignment; see MMIO register $2101. Sprite alignment in PPU RAM is somewhat complicated; refer to other docs
d) Palette is stored independently elsewhere (i.e. not in PPU RAM), and specific MMIO registers are used to interface with it

All backgrounds/sprites/everything share the same PPU RAM, and with higher bit depths on the SNES than the NES, it can be very easy to run out of PPU RAM (considering alignments, etc.).

Mirroring/etc. is controlled via MMIO registers as well (commonly called "SC size"), with native support for 1x1, 1x2, 2x1, and 2x2 (i.e. 4-screen). Larger sizes require more PPU RAM, obviously.

2. How the data is used/accessed/utilised depends on video mode (MMIO register $2105) and background number. For example, mode 1 has 3 backgrounds, 2 of which are 4 bits per pixel, with the 3rd BG being 2bpp.

3. SNES documentation and MMIO registers often refer to things/offsets __in words__, not bytes. As such, you'll become extremely reliant on macros to do the byte-to-word conversions, and will often spend time debugging problems relating to this when using PPU RAM viewers and so on (some show things in "raw values the PPU has", others show things in bytes, some intermix both). Here are 4 ca65 macros I use, and some equates, with some examples, for mode 1 (I chose not to include details about BG3):

Code:
.define ppuaddr(addr)             (addr / 2)
.define bgmap(addr, size)         ((((addr / 2) & $FC00) >> 8) | size)
.define bg12chr(bg1addr, bg2addr) (((bg2addr / 2) >> 8) | ((bg1addr / 2) >> 12))
.define bg34chr(bg3addr, bg4addr) (((bg4addr / 2) >> 8) | ((bg3addr / 2) >> 12))
SC_SIZE_32X32         = %00
SC_SIZE_64X32         = %01
SC_SIZE_32X64         = %10
SC_SIZE_64X64         = %11

bg1mapaddr  = $0000          ; $0000-0FFF: BG1 map, 2 horizontal screens
bg2mapaddr  = $1000          ; $1000-17FF: BG2 map, single screen
bg1chraddr  = $2000          ; $2000-xxxx: BG1 CHR data
bg2chraddr  = $6000          ; $6000-xxxx: BG2 CHR data

sep #$30    ; 8-bit A/X/Y
rep #$10    ; 16-bit X/Y

lda #bgmap(bg1mapaddr, SC_SIZE_64X32)
sta $2107
lda #bgmap(bg2mapaddr, SC_SIZE_32X32)
sta $2108

lda #bg12chr(bg1chraddr, bg2chraddr)
sta $210B

ldx #ppuaddr(bg1mapaddr)
stx $2116
...

ldx #ppuaddr(bg1chraddr)
stx $2116
...

The model used on the SNES is that since ROM can be so large, and native DMA transfers between CPU addressing space (e.g. ROM) and PPU are available, don't be afraid to use ROM space for all your stuff. You have a lot more breathing room that on the NES.


Top
 Profile  
 
PostPosted: Mon Jul 29, 2019 10:20 pm 
Offline
User avatar

Joined: Fri Mar 16, 2018 1:52 pm
Posts: 98
Location: Finland
Okay, I think I now understand how the SNES memory space works. I also found a text document that has memory maps for both LoROM and HiROM. I need probably need to refer to it in the future.


Top
 Profile  
 
PostPosted: Mon Jul 29, 2019 10:40 pm 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 8559
Location: Seattle
I would strongly recommend using tepples's memory map diagrams because we've had problems with some of the other depictions of this being confusing, or wrong, or both.


Top
 Profile  
 
PostPosted: Mon Jul 29, 2019 10:46 pm 
Offline

Joined: Fri Jul 04, 2014 9:31 pm
Posts: 1081
If I could recommend a few sources...

https://wiki.superfamicom.org/tags/reference

In particular,
https://wiki.superfamicom.org/memory-mapping
https://wiki.superfamicom.org/registers
https://wiki.superfamicom.org/backgrounds
https://wiki.superfamicom.org/sprites
https://wiki.superfamicom.org/dma-and-hdma
and
https://wiki.superfamicom.org/65816-reference
if you need it.

Lots of great information on there. A lot of it is based on anomie's docs, but there are some original contributions.

Also: https://problemkaputt.de/fullsnes.htm is nocash's doc, which is more recent than anomie's stuff and contains (IIRC) some info that isn't in the above. I find it harder to navigate, but maybe that's just me.

If you already know about these, great.


Top
 Profile  
 
PostPosted: Tue Jul 30, 2019 10:34 am 
Offline
User avatar

Joined: Fri Mar 16, 2018 1:52 pm
Posts: 98
Location: Finland
By the way, since portion of the RAM is called "Low RAM", does it differ in any way from the rest of the RAM available?


Top
 Profile  
 
PostPosted: Tue Jul 30, 2019 10:49 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 21591
Location: NE Indiana, USA (NTSC)
No. Low RAM is just the 8K mirror of $7E0000-$7E1FFF that appears in banks $00-$3F and $80-$BF. It has the same "slow" (8 master clocks) speed as banks $7E and $7F.

_________________
Pin Eight | Twitter | GitHub | Patreon


Top
 Profile  
 
PostPosted: Tue Jul 30, 2019 10:50 am 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 8559
Location: Seattle
It's available in multiple difference places because several instructions can only access things in bank 0, and many instructions can only access things within the same program ("K") or data ("B") bank.


Top
 Profile  
 
PostPosted: Tue Jul 30, 2019 12:25 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 2563
Location: DIGDUG
Do you have to put the stack and direct page in the lowRAM?

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
PostPosted: Tue Jul 30, 2019 12:28 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 21591
Location: NE Indiana, USA (NTSC)
You can place them anywhere in bank $00. But on the Super NES, under the standard cartridge memory mapping, the most useful place for the stack is low RAM, and the most useful places for the direct page are low RAM and the DMA registers.

_________________
Pin Eight | Twitter | GitHub | Patreon


Top
 Profile  
 
PostPosted: Tue Jul 30, 2019 1:17 pm 
Offline

Joined: Fri Jul 04, 2014 9:31 pm
Posts: 1081
And the PPU registers, depending on what you're doing. If you happen to need fast access to a data table in ROM, you can use direct page for that too, as long as the cart mapping puts the data you want in bank $00.

The great part about direct page is that it's fairly quick and painless to move it, so you don't have to settle on one setting and leave it there for the whole game. In fact you can use it almost as a third index register, which then provides the ability to do nested free indexing because most direct-page instructions have indexed variants. You just have to get in the habit of pushing and pulling D in interrupts.

But yeah, the stack should probably go in RAM...


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 28 posts ]  Go to page 1, 2  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: 93143 and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group