why is the ROM on the end of the memory map?

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
why is the ROM on the end of the memory map?
by on (#198276)
I don't get why Nintendo decided to have the ROM on the end of the NES memory map rather then in the front. Wouldn't it make programming it a whole lot easier? You wouldn't have to .base to get all of the code in the right address. Another great advantage would be that you would have zero-page in the ROM. Wouldn't having that make programming a whole lot easier? All you would have to do to let's say copy a bunch of .db statements into the nametables would be this simple loop,
Code:
.db $a bunch of numbers
Loop:
  LDA $db address,X
  STA $2007
  INX
  CPX EndPoint
  BNE Loop

That would mean that you could have larger levels with less space. Maybe they thought that zero-page RAM was more important? Of course, I don't often find myself needing to copy large amounts of the same data to RAM.
Re: why is the ROM on the end of the memory map?
by on (#198277)
ROM is at the end of the memory map because the processor requires the interrupt vectors to be at $FFF8-FFFF and the stack to be at $0100-01FF. It wasn't really Nintendo's decision.
Re: why is the ROM on the end of the memory map?
by on (#198278)
then what purpose do .db statements provide? I mean I guess if you want to load registers with constant values from the ROM and have names for the numbers without using zeropage, but if you ask me, it just uses an extra byte in the ROM for the other half of the address. Another situation where having the NES run off of a z80 would've been useful.
Re: why is the ROM on the end of the memory map?
by on (#198279)
Zero page RAM is definitely more useful than zero page ROM.

I mean, on the 6502 you're limited to 256 bytes in zero page. Even in your example, that's not enough to store a single nametable, even if that's all you used zero page for! You'd lose almost all of the use of the fastest memory and instructions on the system for the sake of one copy loop for a quarter of a nametable. And most programs need to do a whole lot more than that. Aside from hardcoded values (which would have to somehow overlap with the quarter of your nametable) you wouldn't be able to use the indirect indexed addressing modes at all.

And any data that you might want in your ROM zero page you could always...just copy to a RAM zero page initially, instead? There's a one-time cost there, I s'pose, but the cases where you'd want this and that'd be a problem are vanishingly small and can't hope to compete to all the cases where you'd want RAM zero page.
Re: why is the ROM on the end of the memory map?
by on (#198280)
DementedPurple wrote:
(ZP ROM)

That's a truly bizarre idea. The NES could have mapped ROM to the ZP if it wanted, but that would not have been a sane design choice at all.

Most games have a lot more than 256 bytes of data. Even a nametable is 1024 bytes alone. What use is such a small space for storage?

Programs need RAM variables. They're accessed much more frequently than read-only data. The ZP is an optimization for those.

FWIW you can put your sprite buffer in ZP if you want.

DementedPurple wrote:
then what purpose do .db statements provide? I mean I guess if you want to load registers with constant values from the ROM and have names for the numbers without using zeropage, but if you ask me, it just uses an extra byte in the ROM for the other half of the address. Another situation where having the NES run off of a z80 would've been useful.

I don't know what you think .db does, or why you think it's related to the ZP at all. It simply stores a byte in ROM. I can't comprehend what alternative you're comparing it to?

If you have a bunch of bytes in a .db array, you use a loop to iterate through them. That it's a 2-byte address isn't really a problem at all because there's only one LDA in the loop. If it's not an array, if it's a single byte, you would just use the immediate form LDA #byte instead of fetching from a .db elsewhere.
Re: why is the ROM on the end of the memory map?
by on (#198285)
I suppose it would be nice if the PPU registers were mapped to zeropage.
Re: why is the ROM on the end of the memory map?
by on (#198286)
rainwarrior wrote:
That's a truly bizarre idea. The NES could have mapped ROM to the ZP if it wanted, but that would not have been a sane design choice at all.

I should clarify, though, that this opinion on design sanity is limited to just the fixed ZP of the 6502.

The 65816's movable "direct page" would actually be very sensible to temporarily move into ROM in many situations.

pubby wrote:
I suppose it would be nice if the PPU registers were mapped to zeropage.

Yeah, that sounds like a good trade to me.
Re: why is the ROM on the end of the memory map?
by on (#198287)
If ROM was mapped to ZP, you wouldn't be able to use dynamic pointers, and constant pointers are completely pointless, since you could just as well use absolute addressing. The stack would also be ROM, making it completely useless (except for reading 256 bytes from ROM using PLA). The 6502 was designed to have RAM on the lower part of the address space, there's no way around that.

PPU registers in ZP (as are the TIA registers in the Atari 2600) would be cool! We'd be able to transfer more data during vblank, and raster effects would be slightly easier to time. The writes could even go through to RAM so you could "read back" values written to write-only registers.
Re: why is the ROM on the end of the memory map?
by on (#198288)
Quote:
you can put your sprite buffer in ZP if you want.


I've thought about putting the OAM buffer in the stack. It's not as ridiculous as it sounds, you just need to make sure your stack is nearly empty at the point you push the buffer to the OAM. You might have to shuffle a few bytes around before and after that, and limit your # of sprites to 56. But, it might potentially free up some extra RAM.

Edit. But don't put the sprite buffer in the zero page. That would be dumb.
Re: why is the ROM on the end of the memory map?
by on (#198291)
dougeff wrote:
But don't put the sprite buffer in the zero page. That would be dumb.

At the cost of tremendous inconvenience you could save up to 256 cycles per frame on the STAs. ;)

Though maybe if the sprite tile X/Y was also each game object's internal X/Y coordinate there's a a lot more access where you can save by operating on the in place. Could be pertinent in a game where everything is a single 8x8 sprite tile?

(It was not a serious suggestion though.)

dougeff wrote:
I've thought about putting the OAM buffer in the stack.

Sort of interesting to think of the stack and OAM buffer as a temporary space that you don't need all the time. If you do your sprites last before waiting on the NMI, seems like that would be somewhat doable. Temporarily shifting out some of the stack before the DMA would be a little fussy, and timing would be strict, but sure it could actually be a good use especially if your RAM budget is really tight.
Re: why is the ROM on the end of the memory map?
by on (#198292)
I think Hot Seat Harry by Memblers puts its display list in zero page, but then a 1K game is simple enough to 1. need it and 2. be able to get away with it.
Re: why is the ROM on the end of the memory map?
by on (#198293)
dougeff wrote:
But don't put the sprite buffer in the zero page. That would be dumb.

I think using the stack is way dumber. If you use ZP, at least you can reliably make the Y coordinate >= 239 to hide unused sprites, and use the remaining 3 bytes of each sprite freely. If you use the stack page, however, setting the Y coordinate will be much harder, since normal stack usage will constantly temper with the Y coordinates of unused sprites.

I fail to see why you'd use either for OAM though. Indexed ZP addressing is as slow as absolute indexed addressing, so unless you're using hardcoded OAM positions (which you shouldn't do due to sprite cycling and dynamic objects), there's absolutely no speed improvement. The stack on the other hand is significantly faster to write to, at 3 cycles per byte and free indexing thanks to the stack pointer, but only if you use it sequentially from $ff down, so not particularly useful if you need more advanced sprite cycling.

If you're tight on RAM, you can always get 3 extra bytes (and 4 bits of the Y coordinate, if you need them that badly) for each OAM entry you sacrifice, no matter where the OAM page is. You can also safely use a significant portion of page 1 for other things. I often dedicate only 40 or so bytes to the actual stack.

Again, putting the OAM in page 1 is a terrible idea because the portion that's not used for sprites still need valid Y coordinates >= 239 so you don't end up with garbage sprites on the screen, and guaranteeing those valid Y coordinates is hard with the stack pointer going up and down. Even the 3 bytes pushed when an NMI happens could corrupt one of the Y coordinates. Even if you were able to do it (the NMI wouldn't corrupt the Y coordinate of OAM slot 63 if the stack was completely empty when the NMI fired), I find all the stack manipulation necessary for this to work really off-putting, and for no significant reward.
Re: why is the ROM on the end of the memory map?
by on (#198295)
Well, I wouldn't store entire nametables in zero-page, I would instead have smaller pre-determened patterns that would go together to make a level.
Re: why is the ROM on the end of the memory map?
by on (#198296)
And who in Nintendo Headquarters thought it was a good idea to have OAM be dynamic RAM? That just makes things a whole lot harder. Of course, I'd imagine there was a reason for not using Static RAM.
Re: why is the ROM on the end of the memory map?
by on (#198297)
To the contrary, everything should be DRAM.

DRAM is cheaper (edit: cheaper=smaller per bit; in the 2C02 each bit of SRAM is 174% the area of each bit of DRAM), and in the NMOS technology that's used in the NES it's even lower power.

Now, why did Nintendo have a buggy DRAM controller inside the PPU? That's a valid question. But not really different from any of the other "why hardware bug" questions.
Re: why is the ROM on the end of the memory map?
by on (#198298)
tokumaru wrote:
Indexed ZP addressing is as slow as absolute indexed addressing

True for LDA, but with STA or INC it's one cycle faster.
Re: why is the ROM on the end of the memory map?
by on (#198307)
You're right, I forgot to compare STA.

Anyway, no matter what you put there, I think that mapping ROM to ZP is a HUGE waste. Loading from ZP is only faster if you don't use an index, which means you need to know the address you're going to read at assembly time. Since it's ROM, if you know the address you know the value that's there, so you might as well use immediate addressing and get the value loaded even faster!

But even if for some miracle you made anything simpler/faster with a particularly magical set of 256 bytes of ROM, that would hardly justify sacrificing the use of pointers. Without pointers, certain tasks would be much harder or would need more code.

If you think that ROM in ZP provides any sort of advantage over the normal setup, that just shows that you still don't get how the 6502 works and how CPU resources are applied to the various tasks necessary in a game.