3

The SNES has a PPU (Picture Processing Unit) which comprises VRAM, OAM (Object Attribute Memory), and CGRAM (Color Graphics/Palette RAM). These are used to represent tiles, tile maps; attributes for sprites; and color palettes, respectively.

The VRAM contains a 2D array which represents a map of tiles that are displayed on the screen (in four background layers, depending on the current mode, not relevant here).

In https://emu-docs.org/Super%20NES/General/snesdoc.html#Reg2116 there is a pretty good overview of how this works:

It states that each entry in the tile map contains this:

High     Low          Legend->  c: Starting character (tile) number
vhopppcc cccccccc               h: horizontal flip  v: vertical flip
                                p: palette number   o: priority bit

It then goes on to say that the following formula can be used to calculate the address of the character:

address_of_character = (base_location_bits << 13) + (8 * color_depth * character_number);

There is also an example:

For example, if base location 1 is selected, the color depth for the tile map is 4 bits (16 colors), and character number 1 is selected, the address will be (1<<13)+8*4*1 = 8224.

However, it then states:

Note that the word address entered into the VRAM address register will be half of that, or 4112.

1: Why is it half?

2: Why is the color depth 4 bits in this example?

3: How is color depth selected or derived, in general?

I've searched through the hardware registers: https://en.wikibooks.org/wiki/Super_NES_Programming/SNES_Hardware_Registers but I don't seem to find anything regarding color depth nor palette. This leads me to believe that the color depth is derived based on the current mode and perhaps something else. Please correct me.

1 Answer 1

4

1: Why is it half?

Erm, half as in halving like in divided by two (aka shifted by 1)? As described it's a word address, not an address of a word (or a byte address). (*1)

The example does illustrate this quite well by coming up with the (byte address) 8224, which turned into a word address (4112, exactly half, isn't it?) is to be stored in the register.

2: Why is the color depth 4 bits in this example?

Beside the obvious why not, it helps to create a nice result. In general, an example should always use different values for different parameters for readability and to avoid the usual 1*1=1 problem. In this case it also helps to underline and simplify the example about halving to make it easy to understand (only decimal digits and all power of two).

3: How is color depth selected or derived, in general?

In what context? Basic colour depth is defined by the mode selected.


*1 - Word Address vs. Byte Address

From comments I got the impression that this is maybe hard to grasp for today's programmers, who never ever experienced anything but byte-addressable machines/CPUs. While this would be more of a topic for a (or several) separate question, lets try here:

A word address numbers words as 0,1,2... A byte address does the same with bytes. A CPU with 16 bit memory and byte addressing will end up with the words 0,1,2... at address 0,2,4... In such a system, conversion between byte and word address is done by halving as one word occupies two bytes. Thus word address != address of a word. It has that been since the invention of memory addressing.

Or in other more 'modern' words (and I really hate to add it, as it's like explaining earth rotation using flat-earthers' vocabulary) think of memory like arrays in C. Some byte array at address 0 will number it's elements as 0,1,2... and they end up at a memory offset (address) of 0,1,2... A similar array with words will number them as well as 0,1,2... but now they end up at offset 0,2,4...

Defining such a 16 bit word, byte addressable memory in C might look like this:

union Memory
 {
  short AsWords[4]; // The Word Memory 
  char  AsBytes[8]; // overlayed with Byte Addesses
 } foo;

foo.AsBytes[4]will here resolve to an offset of 4, while foo.AsWords[2] will also produce an offset of 4. In this example the first is a byte address and the second a word address, both resolved to a byte address withing a byte addressable word orientated memory. But a programmer using a word will always use an index halve of what the bytewise memory address is.

This also shows the reasoning for alignment, as with a 16 bit data path words can be read at the same timing as bytes.

From today's perspective people often have a hard time to understand what a game changer the application of byte addressable word memory was, when Gene Amdahl made it a fundamental part of the /360 design. Today it's taken for granted that memory is seen not only as bytes, but words may reside anywhere. Completely ignoring that it took two major steps in CPU design to archive it: Byte addressing, available due a fitting ISA and misaligned data.

While the first is a real advancement in computer design, the latter not only required mostly useless (and back then large) hardware add-ons for minor gain, but also opened Pandora's box by encouraging to lazy programming, resulting in the need of even more hardware to cover the now common penalties associated.

11
  • 2
    @AlphaCentauri It's a basic concept which I had assumed everyone in programming knows - well, maybe it's jut olt grunts likeme - so I added some description to a footnote, as it's too much for a comment - and maybe also helpful to other readers.
    – Raffzahn
    Aug 2, 2018 at 15:59
  • 1
    Sorry I didn't mean to be ignorant, I like older systems, just don't have the knowledge. Thanks for your answer. Aug 3, 2018 at 8:54
  • 1
    @Raffzahn Excellent explanation of word addressing, but I am curious about your last paragraph; granted that byte addressing was a significant optimization for computers that spend much of their time handling ASCII text, and that you still need to be able to read words, are you saying the ability to read words from misaligned addresses was an important invention? (I ask because in my experience that is a waste of silicon; it has to be in the CPU for backward compatibility, but you always align things so it never actually gets used.)
    – rwallace
    Aug 3, 2018 at 23:02
  • 1
    @rwallace Yes, in this context there are two (byte adressable (word) memory, and missalligned access). And I'm with you that the second is more of an unneccessary tax payed to pamper lazy programmers - not even compatibility, as alignment was first, being law, while unaligned is the new hell. I though my rather downward wording(useless, lazy) does transmit that point. Bottom line, while the first is genious, the later is hell, but nonetheless an important one, no matter if I like it or not (Personal story, even when /370 became enabled to do unaligned loads, I refuse to use them until today)
    – Raffzahn
    Aug 4, 2018 at 0:24
  • 1
    @Jules Not realy, as the compatibility with 8080 code is only partitial, and only for automatic source lever converstion. Thus converting a MOV HL,WORDto a MOV BL,WORD ; MOV BH,WORD+1 is as fine as the requirement of replacing PUSH PSW with LAHF ; PUSH AX. Isn't it? --- In case of an extended architecture (32 to 64 bit), aligned (old) data will always stay aligned. A 32 bit word, aligned to 32 bit on a 64 bit machine is still fetchable in a single cycle, or do I miss anything?
    – Raffzahn
    Aug 4, 2018 at 16:59

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .