Page 5 of 18

Posted: Sun Jan 16, 2011 4:06 pm
by FinalZero
Me, misspelling DPCM. Delta Pulse Code Modulation. It is how the NES can play raw sound samples. The APU uses DMA to pull the samples from the high-end of the CPUs address space.
Ok.
The PPU uses two 4K banks, one for background tiles, one for sprites. The PPU can be configured to pull tiles and sprites from the same 4K bank, or from either bank. Together, the PPU "sees" 8K ($0000 to $1fff in the PPU's address space). This memory lives on a cart as ROM or RAM and is called "CHAR-xxx". Physically, on the bus between the NES and the cart, the PPU controls 13 address lines (2^13 = 8192 = 8K bytes (well, technically, the ISO unit is "KiB", not "KB", but we'll ignore that here)) and reads 8 data bits. There are other control signals (RW, /CE) used to tell the memory circuit if the PPU wants to read or write, and "enable" the chip or not.
Ok. While we're on the topic of tiles and sprites, is there any way to just grab and display a 4x4 tile/sprite? or is 8x8 the smallest size that can be done? I'm wondering because if so, then smoother fonts could be created and used, rather than the typical ugly monospaced 8x8 one...
I'm sorry. I don't understand your question. What does _what_ do? I suppose that my example won't make any sense to you if you have not played FF1.
I have played FF1, but not for the NES. I'm trying to ask how they do store the data if they can't store it in one or two char banks. Also, do you mean the monster graphics themselves, or the possible combinations of monster the player's party might meet? If the latter, why is that stored in char rom? It's not graphical.
Its all semantics. The cc65 compiler suite uses the term "segment", which can be of arbitary length. The NES simply has address ranges and two buses (CPU and PPU). The term "bank switching" means that a memory controller (ie, mapper chip) can swap memory out from underneath the CPU. Banks are typically large, and have sizes that are exact powers of 2, and are aligned on memory address boundaries that are powers of 2.
So, what does one do if one needs data from two separate banks? Load it from one, switch to the other, and then load the rest?
In a modern computer, the programs "data segment" is copied to ram. "RODATA" and "TEXT" (an archaic term for "code") are marked read-only (if the cpu's mmu supports that). "Data" is loaded just above the end of the "text", and BSS above that. The app's heap starts above BSS and grows up, and the stack starts at the end of the processes address space and grows down. When the heap and stack collide, bad shit happens.

In the NES is bit different. There is no "program loader" that places different segments into memory. Your reset routine _IS_ the loader, so to speak. Typically, a NES program will contain CODE and RODATA in ROM; use all RAM as BSS (but its not called that) and contain no traditional "DATA" segment. However, there is nothing to stop you from emitting a large chunk of "DATA" into your ROM and then copying it into RAM, where it can then be modified and treated as "DATA" like a C program executing on Unix would.
Ok, so "RODATA" is read-only data (in the context of FF) like monster stats (which change), "DATA" is data like character stats (which don't change), "CODE" is like the battle/menu routine, and "BSS" is the ram? And these are only conventions suggested to be followed, not laws that the assembler enforces?

Posted: Sun Jan 16, 2011 4:35 pm
by tokumaru
FinalZero wrote:Ok. While we're on the topic of tiles and sprites, is there any way to just grab and display a 4x4 tile/sprite? or is 8x8 the smallest size that can be done?
8x8 is the smallest unit. For sprites you can make part of the 8x8 tile transparent so objects can appear to be any size you want, but the backgrounds are always composed by 8x8-pixel blocks.
I'm wondering because if so, then smoother fonts could be created and used, rather than the typical ugly monospaced 8x8 one...
If you use CHR-RAM you can manipulate graphics to the pixel level, but because of space and speed constraints, there are severe limitations to what you can do with that.

To write text with proportional fonts you have to use CHR-RAM, reserve a number of tiles that span the maximum length of your text, and in order to write the text you'd update the pattern tables, rather than the name tables. Since there are only 256 tiles for the background, you can conclude that this will waste a lot of tiles quickly.

Under normal circumstances, those 256 tiles are not enough to make an entirely unique screen (such screen would need 960 tiles). But if your graphics use only 2 colors (which is usually the case with text), you can use a few tricks. First, NES tiles have 4 colors, so they use 2 bits per pixel. 2-color graphics need only 1 bit per pixel, so you can actually store 2 1-bit images in 1 tile (to display one image or the other you have to use different palettes), which basically doubles the tile count to 512. The next trick is to switch to the other half of the pattern tables halfway through the rendering of the screen, which will result in 1024 1-bit tiles, enough for an unique screen with no repeated tiles.

So yeah, it's possible to write a whole screen of text with proportional fonts. In fact, there was some talk about this a while ago when someone wanted an e-book reader made for his portable NES clone. I don't think this would be practical in actual games though.
I have played FF1, but not for the NES. I'm trying to ask how they do store the data if they can't store it in one or two char banks. Also, do you mean the monster graphics themselves, or the possible combinations of monster the player's party might meet? If the latter, why is that stored in char rom? It's not graphical.
I haven't played FF1, but the thing with CHR-ROM is that the tile combinations you can make are limited. The maximum CHR division in existing mappers is 4 1KB banks per pattern table. This means that there are 4 switchable blocks. If you wanted to combine enemies for example, you'd have to map a different enemy to each slot. But what happens if you want to combine more than 4 different enemies? You can't with blocks that size, unless you start hardcoding the combinations in a huge CHR-ROM chip, which might not even be possible depending on the number of combinations. The solution in this case is to use CHR-RAM, so that each tile can be edited freely and you can make all the combinations of graphics you want, as long as they add up to 256 tiles.
So, what does one do if one needs data from two separate banks? Load it from one, switch to the other, and then load the rest?
Yeah, this can get complicated depending on the number of switchable and fixed banks each mapper has. This is something you have to take into consideration when designing your program.

In my current project for example (UxROM: 2 16KB slots, one fixed, one switchable), the main game engine is in the fixed bank, so that it can read level maps and things like that from all the other banks. Other things that are more or less self contained (i.e. don't need to access other banks) stay in switchable banks too (like the music engine, navigation menus/screens, etc).

Of course there are ways to access anything from anywhere by using trampoline code (i.e. call a routine in the fixed bank which will switch banks, read the data, switch back and finally return the data), but that can be very slow because of all the overhead.

Posted: Sun Jan 16, 2011 6:02 pm
by FinalZero
I wasn't thinking of a proportional font though, but only a font that *seems* proportional, when in fact it has a fixed-width of 4. So a letter like 'i' would take up 1x2 (1 wide, 2 tall) 4x4 pixel tiles, but 'm' or 'w' would take 3x2. But this seems to be impossible since you said the smallest unit is 8x8. ... I remember that the fan translation of FF3j made some special tiles so that three skinny letters ('i' or 'l') could fit across two tiles instead of three. Of course, the problem with this is that it takes up more tiles, that one can only choose a limited amount of combinations, and it's practical uses are limited to skinny letters like 'i' and 'l', or shortening specific long words. ... Was/is the SNES simply fast enough that more games than before decided to use proportional fonts?
Under normal circumstances, those 256 tiles are not enough to make an entirely unique screen (such screen would need 960 tiles). But if your graphics use only 2 colors (which is usually the case with text), you can use a few tricks. First, NES tiles have 4 colors, so they use 2 bits per pixel. 2-color graphics need only 1 bit per pixel, so you can actually store 2 1-bit images in 1 tile (to display one image or the other you have to use different palettes), which basically doubles the tile count to 512.
I understand how that works, but at the same time I'm not sure how that'd work. Wouldn't you have to clear either the upper or lower bits depending or whether your reading the tile or its shadow?
Yeah, this can get complicated depending on the number of switchable and fixed banks each mapper has. This is something you have to take into consideration when designing your program.

In my current project for example (UxROM: 2 16KB slots, one fixed, one switchable), the main game engine is in the fixed bank, so that it can read level maps and things like that from all the other banks. Other things that are more or less self contained (i.e. don't need to access other banks) stay in switchable banks too (like the music engine, navigation menus/screens, etc).

Of course there are ways to access anything from anywhere by using trampoline code (i.e. call a routine in the fixed bank which will switch banks, read the data, switch back and finally return the data), but that can be very slow because of all the overhead.
How much does bank switching slow things down?

...

If nobody minds, I'm going to try posting some code here so we can discuss what exactly I need to program next to work my way toward displaying "Hello World". Perhaps uploading the files somewhere would be a better idea?

-----

Also, is there any way to raise the number of posts that are visible per page on this board?

Posted: Sun Jan 16, 2011 8:23 pm
by tokumaru
FinalZero wrote:Was/is the SNES simply fast enough that more games than before decided to use proportional fonts?
It's significantly faster when it comes to updating tiles (I believe it even has DMA for that), and it also has much more VRAM.
I understand how that works, but at the same time I'm not sure how that'd work. Wouldn't you have to clear either the upper or lower bits depending or whether your reading the tile or its shadow?
Conveniently enough, NES tiles are stored in planes, 8 bytes for the fist plane followed by 8 bytes for the second, so if you open them in a tile editor an set the format to 1-bit, what you'll see is that each NES tile becomes 2 1-bit tiles (without any conversion necessary, the difference is just how the data is interpreted). Pixels can have values ranging from 0 to 3. If a pixel is 0, it's cleared in both planes, if it's 3, it's set in both planes, and if it's 1 or 2 it's set in only one of the planes. That tells you how to configure your palettes so that one image or the other is displayed. Say you want to have black text on white background. Color 0 would always be white, because that's the color that will be picked when both planes have clear pixels. Similarly, color 3 will always be black. As for colors 1 and 2, one will be white and the other will be black, depending on which plane you want to show. Setting one of those colors to white will effectively "hide" one of the planes, so that only the other one is visible.
How much does bank switching slow things down?
It depends. You can read a single byte from PRG-ROM in 4 cycles with LDA $8040, for example. If you wanted to load a byte from an arbitrary bank, you'd have to switch that bank in first, which would take at least 8 cycles in an UxROM game, so it would take you a total of 12 cycles, 3 times more, to read a single byte. Depending on the mapper, switching a new bank might take more time, and if you want to do things like remember the previous bank and switch it back after reading the data, the overhead will be huge (of course, the overhead will not be as significant if you are reading 200 bytes, as opposed to only one).

So trust me, reading lots of data from banks all across the ROM is not something you want to do in the middle of your game loop, because there will be a huge impact on the speed. Try to organize your code and data in a way that minimizes bankswitching as much as possible. To give you an idea, it would be acceptable to bankswitch a couple dozen times every frame (i.e. each iteration of your game logic), but if you are doing it hundreds of times per frame, there's probably something wrong.
If nobody minds, I'm going to try posting some code here so we can discuss what exactly I need to program next to work my way toward displaying "Hello World". Perhaps uploading the files somewhere would be a better idea?
People often post code in sites like this. If you have a number of source files though, it would probably be better to upload a ZIP file somewhere.
Also, is there any way to raise the number of posts that are visible per page on this board?
I never actually looked for an option to do this, but I don't think this is possible.

Posted: Sun Jan 16, 2011 8:38 pm
by tepples
FinalZero wrote:Ok. While we're on the topic of tiles and sprites, is there any way to just grab and display a 4x4 tile/sprite? or is 8x8 the smallest size that can be done? I'm wondering because if so, then smoother fonts could be created and used, rather than the typical ugly monospaced 8x8 one...
It's possible to render proportional text to CHR RAM. A box for three lines of a character's dialogue might take up 60 of your background tiles (or 30 if you use mid-frame palette hackery), but then those are tiles you don't have to use for 0-9A-Za-z. You'll need it anyway if you plan to produce a version of your game containing Chinese, Arabic, or other complex scripts. Faxanadu, for example, reserves 64 tiles for its text boxes so that the Japanese version can display kanji.
I'm trying to ask how they do store the data if they can't store it in one or two char banks. Also, do you mean the monster graphics themselves, or the possible combinations of monster the player's party might meet?
The latter. With CHR ROM, one can't arbitrarily display from different parts of CHR ROM; one is limited by the number of pages that can be selected at once. But with CHR RAM, the program can copy any combination of monster graphics into memory at once.
So, what does one do if one needs data from two separate banks? Load it from one, switch to the other, and then load the rest?
If you're referring to PRG data, then for the most part, yes. But with quite a few mappers, when you switch to a bank with data, you also switch right under your own feet because the program itself is in a switchable bank. So there are pieces of the program that have to be at the same place in all banks. This is the "trampoline" that tokumaru was talking about, which lets subroutines in different banks call each other.

And as for rapid fire bankswitching, there are exceptions to nearly every rule. Cosmic Epsilon, for example, abuses the PPU, MMC, and CHR ROM to act together as a makeshift texture mapping unit, and it switches on every scanline. But in more typical use, MMC1 is the slowest to switch banks, taking 9 instructions; it's far faster on most other mappers (2 on most discretes; 3 on MMC3).
Ok, so "RODATA" is read-only data (in the context of FF) like monster stats (which change), "DATA" is data like character stats (which don't change), "CODE" is like the battle/menu routine, and "BSS" is the ram? And these are only conventions suggested to be followed, not laws that the assembler enforces?
DATA is anything copied into RAM at reset time. You shouldn't have much need for this, as things would usually get copied at the start of a game, the start of a level, etc.

Posted: Mon Jan 17, 2011 2:05 am
by thefox
tepples wrote:
Ok, so "RODATA" is read-only data (in the context of FF) like monster stats (which change), "DATA" is data like character stats (which don't change), "CODE" is like the battle/menu routine, and "BSS" is the ram? And these are only conventions suggested to be followed, not laws that the assembler enforces?
DATA is anything copied into RAM at reset time. You shouldn't have much need for this, as things would usually get copied at the start of a game, the start of a level, etc.
However it should be noted that some CC65 linker configs out there use DATA as the bss segment name, as CC65 doesn't force any of the segment parameters.

CODE = read-only code
RODATA = read-only data, goes in to ROM, so you can't modify it
BSS = uninitialized data, this is RAM that you don't care what the initialization value is (but it's usually cleared to 0 on reset)
DATA = initialized data (in RAM), the initialization values are copied from ROM to RAM on reset, however you have to do that YOURSELF using symbols that the linker supplies

Posted: Tue Jan 18, 2011 6:20 pm
by FinalZero
Conveniently enough, NES tiles are stored in planes, 8 bytes for the fist plane followed by 8 bytes for the second, so if you open them in a tile editor an set the format to 1-bit, what you'll see is that each NES tile becomes 2 1-bit tiles (without any conversion necessary, the difference is just how the data is interpreted). Pixels can have values ranging from 0 to 3. If a pixel is 0, it's cleared in both planes, if it's 3, it's set in both planes, and if it's 1 or 2 it's set in only one of the planes. That tells you how to configure your palettes so that one image or the other is displayed. Say you want to have black text on white background. Color 0 would always be white, because that's the color that will be picked when both planes have clear pixels. Similarly, color 3 will always be black. As for colors 1 and 2, one will be white and the other will be black, depending on which plane you want to show. Setting one of those colors to white will effectively "hide" one of the planes, so that only the other one is visible.
I understand it now. Wouldn't a downside be though that one needs to devote 2 palettes to displaying text if one needs tiles from both sets though?
It depends. You can read a single byte from PRG-ROM in 4 cycles with LDA $8040, for example. If you wanted to load a byte from an arbitrary bank, you'd have to switch that bank in first, which would take at least 8 cycles in an UxROM game, so it would take you a total of 12 cycles, 3 times more, to read a single byte. Depending on the mapper, switching a new bank might take more time, and if you want to do things like remember the previous bank and switch it back after reading the data, the overhead will be huge (of course, the overhead will not be as significant if you are reading 200 bytes, as opposed to only one).

So trust me, reading lots of data from banks all across the ROM is not something you want to do in the middle of your game loop, because there will be a huge impact on the speed. Try to organize your code and data in a way that minimizes bankswitching as much as possible. To give you an idea, it would be acceptable to bankswitch a couple dozen times every frame (i.e. each iteration of your game logic), but if you are doing it hundreds of times per frame, there's probably something wrong.
Ah, ok.
People often post code in sites like this. If you have a number of source files though, it would probably be better to upload a ZIP file somewhere.
I'll probably load it onto my webpage. http://jc.tech-galaxy.com/ That way I can best control how long it's available for. I'll get around to uploading the files eventually.
It's possible to render proportional text to CHR RAM. A box for three lines of a character's dialogue might take up 60 of your background tiles (or 30 if you use mid-frame palette hackery), but then those are tiles you don't have to use for 0-9A-Za-z. You'll need it anyway if you plan to produce a version of your game containing Chinese, Arabic, or other complex scripts. Faxanadu, for example, reserves 64 tiles for its text boxes so that the Japanese version can display kanji.
What do you mean by """mid-frame palette hackery"""?
DATA is anything copied into RAM at reset time. You shouldn't have much need for this, as things would usually get copied at the start of a game, the start of a level, etc.
What would an example of such a thing be?

Posted: Tue Jan 18, 2011 8:47 pm
by tepples
FinalZero wrote:
Color 0 would always be white, because that's the color that will be picked when both planes have clear pixels. Similarly, color 3 will always be black. As for colors 1 and 2, one will be white and the other will be black, depending on which plane you want to show. Setting one of those colors to white will effectively "hide" one of the planes, so that only the other one is visible.
I understand it now. Wouldn't a downside be though that one needs to devote 2 palettes to displaying text if one needs tiles from both sets though?
Using two palettes is excusable if you use mid-frame palette rewrites.
It's possible to render proportional text to CHR RAM. A box for three lines of a character's dialogue might take up 60 of your background tiles (or 30 if you use mid-frame palette hackery)
What do you mean by """mid-frame palette hackery"""?
The palette (PPU $3F00-$3F1F) can be modified whenever rendering is turned off (forced blank or vertical blank). If you do this during draw time (not horizontal or vertical blanking), you get rainbow artifacts in the visible area. Turning on monochrome in PPUMASK while rewriting the palette, as seen in the "Sayoonara" demo by Chris Covell, helps minimize their visibility. But if you just want to display subtitle text in a bottom status bar, something simple like loading eight colors' worth of black-and-white palettes can be done in a couple lines' horizontal blanking.
DATA is anything copied into RAM at reset time. You shouldn't have much need for this, as things would usually get copied at the start of a game, the start of a level, etc.
What would an example of such a thing be?
How well do you know C? It can sometimes be easier to explain ld65 concepts in terms of C, as that's what ld65 was designed around. Segment DATA contains what C would call the values of initialized statically allocated variables, be they global variables or local variables with 'static' storage. But some coding standards discourage initialized declarations, instead preferring to initialize the variables explicitly from 'const' data at runtime. This 'const' data goes in RODATA.

Posted: Tue Jan 18, 2011 10:01 pm
by FinalZero
How well do you know C? It can sometimes be easier to explain ld65 concepts in terms of C, as that's what ld65 was designed around. Segment DATA contains what C would call the values of initialized statically allocated variables, be they global variables or local variables with 'static' storage. But some coding standards discourage initialized declarations, instead preferring to initialize the variables explicitly from 'const' data at runtime. This 'const' data goes in RODATA.
I know about static and const, but I don't understand what that gnu page is saying one shouldn't write. Is it saying don't write something like:

Code: Select all

int f() {
    static int x = 3;
    ...
    x += whatever;
}
but instead?:

Code: Select all

intf() {
    static int x;
    x = 3;
    ...
    x += whatever;
}
(Yes, I know that these functions don't do the same thing. This only underlines that I don't understand what the gnu page is trying to say.)

Posted: Wed Jan 19, 2011 5:49 am
by tepples
The GNU page is supposed to say, as I interpret it:
  • Don't use static variables inside functions.
  • Initialize global variables at the start of main(), so that if you need to initialize them more than once, you can easily refactor that out. This covers the case of, say, returning to the title screen.

Posted: Wed Jan 19, 2011 9:59 am
by tokumaru
tepples wrote:But if you just want to display subtitle text in a bottom status bar, something simple like loading eight colors' worth of black-and-white palettes can be done in a couple lines' horizontal blanking.
You'd actually have to change only the 2 middle colors of the palette, so it might be possible to avoid color artifacts altogether if you do the writes during HBlank.

Posted: Sat Feb 05, 2011 11:27 pm
by FinalZero
Don't use static variables inside functions.
Initialize global variables at the start of main(), so that if you need to initialize them more than once, you can easily refactor that out. This covers the case of, say, returning to the title screen.
Ah, that makes sense now.

-----

Here's a couple more questions:
1) I know that sprites can overlap something in the background, but can they underlap it?
2) Were there any mappers that added capabilities for the PPU to use more than just 4 palettes for the background and 4 palettes for sprites? or perhaps add more than 4 colors per palette? Could a mapper even do such a thing?

Posted: Sun Feb 06, 2011 4:46 am
by Wave
FinalZero wrote:
Don't use static variables inside functions.
Initialize global variables at the start of main(), so that if you need to initialize them more than once, you can easily refactor that out. This covers the case of, say, returning to the title screen.
Ah, that makes sense now.

-----

Here's a couple more questions:
1) I know that sprites can overlap something in the background, but can they underlap it?
2) Were there any mappers that added capabilities for the PPU to use more than just 4 palettes for the background and 4 palettes for sprites? or perhaps add more than 4 colors per palette? Could a mapper even do such a thing?
1) Yes, they can, if you set bit 5 of sprite attribute.
76543210
||||||||
||||||++- Palette (4 to 7) of sprite
|||+++--- Unimplemented
||+------ Priority (0: in front of background; 1: behind background)
|+------- Flip sprite horizontally
+-------- Flip sprite vertically
(from http://wiki.nesdev.com/w/index.php/OAM)


2) Were there any mappers that added capabilities for the PPU to use more than just 4 palettes for the background and 4 palettes for sprites? or perhaps add more than 4 colors per palette? Could a mapper even do such a thing?
I think there's no such mapper. I'm not sure but I don't think it could be done.

Posted: Sun Feb 06, 2011 5:23 am
by FinalZero
1) Yes, they can, if you set bit 5 of sprite attribute.
Ah, I see. Thank you.

I asked because I had this in mind:
Image
Notice how the lower part of the sprite is behind the wall, but upper part is in front of it. For a second I thought they were using a trick like removing the lower part of the sprite (since it's actually composed of 4 sprites, 2 upper and 2 lower) whenever a sprite's location is on a certain tile, but notice how the lower part of the sprite that's behind the transparent pixels of the wall is still visible.

As a side note, while looking at the GBC's specs, I was surprised to find out that it supports 8 palettes each for both the background and sprites (hence my other questions), and that it also has a faster processor (4 times as fast, iirc). I knew it came 10 years after the NES, but I didn't think it was so fast, because it was just a handheld...

Posted: Sun Feb 06, 2011 7:44 am
by Dwedit
The NES supports two kinds of sprite masking.
There's the simple masking where the sprite goes behind everything in the background that's not color #0. Lots of games use this, including Super Mario Bros when you go through a pipe.

Then there's another masking mode where you put a sprite behind the background, then subsequent sprites in the same place are not drawn. Super Mario 3 uses this 'mode' when you hit a question block and a mushroom comes out of it, it puts a dummy sprite behind the question block. The sprites of the mushroom are covered up by the pixels of the dummy sprite. Time Lord also uses this trick as well.
The masking sprite must be set to be behind the background, and must be earlier in the sprite table than the sprite which gets masked.

For example, Here's time lord, and the sprites it draws to pull off a masking effect:
Image
And here's what the masking effects ends up looking like: (not quite the same screenshot, but close enough)
Image


Also, for that GBC screenshot, they are using the feature where every background palette has its own background color (color #0). If you look closely, the background area of that block is all the same color. GBC doesn't do sprite masking the same way the NES does, it only supports the simple Color #0 mode.
The GBA can simulate the NES-style overlapped sprite masking with the GBA's transparency/blending feature, but that's only useful for making NES emulators on the GBA.