Correct way to read the VRAM

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

Post Reply
User avatar
DarkKodKod
Posts: 7
Joined: Wed Sep 19, 2018 8:21 am
Location: Germany
Contact:

Correct way to read the VRAM

Post by DarkKodKod » Sat Jul 11, 2020 4:31 am

Hi All
I want to read what is in the nametable (the exact byte under any nametable address). The problem is that I want to read it not during the NMI because is for some check with collisions against the background. Is it really possible to access the VRAM not in the NMI and not have render glitches ?
and if it possible? what would be the method to do so?

tepples
Posts: 22020
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Correct way to read the VRAM

Post by tepples » Sat Jul 11, 2020 4:36 am

Keep a cached copy of the relevant portion of VRAM in main RAM. Super Mario Bros. keeps a 32x13-cell sliding window, where each cell represents 16 by 16 pixels. RHDE keeps a 32x24-cell window for the playfield, where each cell represents one 8x8-pixel tile.

Or structure the collision data to support random access. Haunted: Halloween '85 and '86 store each level's collision map in part as a list of rectangular slabs in ROM.

User avatar
DarkKodKod
Posts: 7
Joined: Wed Sep 19, 2018 8:21 am
Location: Germany
Contact:

Re: Correct way to read the VRAM

Post by DarkKodKod » Sat Jul 11, 2020 4:40 am

tepples wrote:
Sat Jul 11, 2020 4:36 am
Keep a shadow copy of the relevant portion of VRAM in main RAM. Super Mario Bros. keeps a 32x13-cell sliding window, where each cell represents 16 by 16 pixels. RHDE keeps a 32x24-cell window for the playfield, where each cell represents one 8x8-pixel tile.
I wanted to do it that but because I was using the 8x8 pixels tile, I thought it was a lot of RAM waste but if there is no other way, then I will follow your suggestion

Thanks!

tepples
Posts: 22020
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Correct way to read the VRAM

Post by tepples » Sat Jul 11, 2020 5:08 am

Is your game a scrolling game or a non-scrolling game? Is the playfield logically made of 8x8 pixel, 16x16 pixel, or other size cells? Choosing the best paradigm to fit hardware interaction, the sound driver, and your game state into 2048 bytes of RAM depends on the answers to these questions.

If it helps, here's an executive summary of the memory layout in RHDE:

$0000-$000F Local variables
$0010-$00FF Most commonly accessed variables and entity states
$0100-$01BF Decompression and VRAM transfer buffer
$01C0-$01FF Stack
$0200-$02FF OAM buffer
$0300-$05FF Playfield
$0600-$07FF Entity states; sound driver

User avatar
Bregalad
Posts: 7892
Joined: Fri Nov 12, 2004 2:49 pm
Location: Chexbres, VD, Switzerland

Re: Correct way to read the VRAM

Post by Bregalad » Sat Jul 11, 2020 5:14 am

DarkKodKod wrote:
Sat Jul 11, 2020 4:31 am
Hi All
Is it really possible to access the VRAM not in the NMI and not have render glitches ?
You seem to be confusing NMI with VBlank. NMI is an intereput, one of the 3 supported by the 6502 CPU (NMI, IRQ, Reset). VBlank is an event happening each frame during which no image is rendered and VRAM can be freely accessed by $2006/7.

You cannot read VRAM during rendering/outside of VBlank without causing graphical glitches, that is unless you use forced blanking and then nothing is shown on screen. Whether you use VBlank NMI or not is irrelevant for that matter.

Also, I strongly suggest separating collision data and nametable data written to VRAM. That being said, it's perfectly fine to read data back from VRAM during VBlank and use it for logic during the frame through a buffer system opposite of what is typically done for VRAM updates. The thing is, some people will consider it a waste of time that could be used for VRAM updates - but IMO it's fine to do even if unelegant if that is intended to be used for collision detection.
Last edited by Bregalad on Sat Jul 11, 2020 1:31 pm, edited 1 time in total.

User avatar
Controllerhead
Posts: 103
Joined: Tue Nov 13, 2018 4:58 am
Location: $4016
Contact:

Re: Correct way to read the VRAM

Post by Controllerhead » Sat Jul 11, 2020 8:18 am

DarkKodKod wrote:
Sat Jul 11, 2020 4:31 am
Hi All
I want to read what is in the nametable (the exact byte under any nametable address). The problem is that I want to read it not during the NMI because is for some check with collisions against the background. Is it really possible to access the VRAM not in the NMI and not have render glitches ?
and if it possible? what would be the method to do so?
Personally, i keep track of map / camera coordinates and (re)read level data from ROM instead. Reading anything in VRAM is never really a great idea...
DarkKodKod wrote:
Sat Jul 11, 2020 4:40 am
I thought it was a lot of RAM waste but if there is no other way, then I will follow your suggestion. Thanks!
I don't know what your engine or level data format look like, but, if you want to save RAM at the cost of perhaps burning a few more cycles to reload a piece of your level data, this is probably the way to go.
Image

User avatar
tokumaru
Posts: 11772
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Correct way to read the VRAM

Post by tokumaru » Sat Jul 11, 2020 10:15 am

Doing collisions against graphical data is a poor programming practice in general. Depending on the hardware, game design or graphical style, you may run into cases where tiles need to be reused but with different collision attributes (e.g. a secret passage that looks like a solid wall, or a top-down view that results in objects being partially blocked, etc.).

On the NES in particular, using graphical data for collision is quite prohibitive, since access to VRAM is limited (as you found out) and mirroring all that data in program RAM would consume a ridiculously large chunk of memory. NES games will often do one of these 3 things instead:

1- buffer a partially decoded map in program RAM: emphasis on "partially", meaning that only the area immediately surrounding the player is available at any given time, and it's not fully decoded all the way down to the tile level, it usually goes at most to the 16x16 block level, from which tiles and collision data can be easily extracted.

2- use extra program RAM on the cartridge to hold entire maps: basically the same thing as above, but with more room to work with. If the levels aren't particularly large, complete maps can be in RAM at a time.

3- keep all maps entirely in ROM: this can be done when maps are stored in a format that allows for random access to the data (i.e. fixed compression ratio). Tile data is extracted from a map when scrolling, and collision data is extracted for physics stuff.

It's a good programming practice to keep a game's model (simulated world) separate from its view (graphical representation), so that you don't have to rebuild the entire game in case you decide to render it differently (e.g. when porting it to another system with incompatible video hardware, or changing the view from cross section to top-down, isometric or first person).

tepples
Posts: 22020
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Correct way to read the VRAM

Post by tepples » Sat Jul 11, 2020 3:20 pm

tokumaru wrote:
Sat Jul 11, 2020 10:15 am
It's a good programming practice to keep a game's model (simulated world) separate from its view (graphical representation), so that you don't have to rebuild the entire game in case you decide to render it differently (e.g. when porting it to another system with incompatible video hardware, or changing the view from cross section to top-down, isometric or first person).
I fully agree in the case of PC games, mobile games, fifth generation (Saturn, PlayStation, N64) or later console games, and GBA or later handheld games. Before that, it's good practice but not quite as critical to maintain strict input and output abstraction because you have to rebuild everything anyway when porting a game to another machine with a mutually incompatible instruction set or an entirely different video paradigm (like that of Apple II).

User avatar
Controllerhead
Posts: 103
Joined: Tue Nov 13, 2018 4:58 am
Location: $4016
Contact:

Re: Correct way to read the VRAM

Post by Controllerhead » Sat Jul 11, 2020 4:20 pm

tokumaru wrote:
Sat Jul 11, 2020 10:15 am
It's a good programming practice to keep a game's model (simulated world) separate from its view (graphical representation)
MVC for life!
https://en.wikipedia.org/wiki/Model%E2% ... controller
Image

User avatar
tokumaru
Posts: 11772
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Correct way to read the VRAM

Post by tokumaru » Sat Jul 11, 2020 7:10 pm

tepples wrote:
Sat Jul 11, 2020 3:20 pm
because you have to rebuild everything anyway when porting a game to another machine with a mutually incompatible instruction set
If you're porting NES games to newer platforms you may consider interpreting the 6502 code... Writing a basic 6502 simulator without all the timing constraints sounds easier than reprogramming an entire game. Input and output would consist of native code, using as much of the new hardware as you'd like. If you have enough sub-pixel precision in your fixed-point coordinates, you can even draw graphics in higher resolutions without sacrificing the pixel-perfect movement.

You're right that total separation between game logic and IO isn't always 100% possible in older systems, but in many cases it is doable. If you can do it without sacrificing anything else, you should definitely go for it.

User avatar
DRW
Posts: 1976
Joined: Sat Sep 07, 2013 2:59 pm

Re: Correct way to read the VRAM

Post by DRW » Sun Jul 12, 2020 2:39 am

DarkKodKod wrote:
Sat Jul 11, 2020 4:40 am
I wanted to do it that but because I was using the 8x8 pixels tile, I thought it was a lot of RAM waste but if there is no other way, then I will follow your suggestion
If the collision check is just walkable vs. non-walkable (and not stuff like spikes who take energy away or swamp that makes you walk slower), then you can store one bit per 8x8 tile. Those are then 120 bytes.
My game "City Trouble": www.denny-r-walter.de/city.htm

User avatar
tokumaru
Posts: 11772
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Correct way to read the VRAM

Post by tokumaru » Sun Jul 12, 2020 2:52 am

DRW wrote:
Sun Jul 12, 2020 2:39 am
If the collision check is just walkable vs. non-walkable (and not stuff like spikes who take energy away or swamp that makes you walk slower), then you can store one bit per 8x8 tile. Those are then 120 bytes.
This is a good suggestion. If you really, really must get collision attributes from tile indices, you can get that information while copying the tiles to VRAM and cache only the collision attributes in a smaller table in RAM. Even if you need more states than walkable vs. non-walkable, using 2 bits or even 4 per tile will still result in significant memory savings compared to storing all 8 bits of each tile index.

User avatar
DarkKodKod
Posts: 7
Joined: Wed Sep 19, 2018 8:21 am
Location: Germany
Contact:

Re: Correct way to read the VRAM

Post by DarkKodKod » Mon Jul 13, 2020 1:02 am

Thanks for all of your advises. It is now clear how should I proceed with this. I have a lot of experience with game development but this is my very first game on the NES and I dont know the good practices yet :)

Post Reply