Skip to content

A PLAY EXPERIENCE MAKER'S WORK LOG FOR FUTURE SELF©2001 – 2023 Kyle Li 李肅綱 All Rights Reserved.

8bitworkshop Notes – Display an external Nametable V1

Posted on October 4, 2026October 10, 2026 by admin

Nametable file format:

The ultimate goal is to create an external file that stores all the nametable data.

.export _nametable_0, _nametable_1, _nametable_2, _nametable_3
.export _nametable_4, _nametable_5, _nametable_6, _nametable_7

.segment "RODATA"

_nametable_0: .repeat 30
                  .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$40,$41,$41,$41,$41,$41
              .endrepeat

_nametable_1: .repeat 30
                  .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$40,$41,$41,$41,$41,$41
              .endrepeat

_nametable_2: .repeat 30
                  .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$40,$41,$41,$41,$41,$41
              .endrepeat

_nametable_3: .repeat 30
                  .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$40,$41,$41,$41,$41,$41
              .endrepeat

_nametable_4: .repeat 30
                  .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$40,$41,$41,$41,$41,$41
              .endrepeat

_nametable_5: .repeat 30
                  .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$40,$41,$41,$41,$41,$41
              .endrepeat

_nametable_6: .repeat 30
                  .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$40,$41,$41,$41,$41,$41
              .endrepeat

_nametable_7: .repeat 30
                  .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$40,$41,$41,$41,$41,$41
              .endrepeat

Nametables are stored as raw byte arrays in PRG ROM and copied or decompressed into PPU VRAM when loaded.

  • Uncompressed Nametables ($1,024$ bytes each): I can store roughly 15 to 20 uncompressed Nametables before filling up your 32 KB PRG ROM (leaving ~12 KB for game engine code, physics, music, and logic).
  • RLE-Compressed Nametables (~150 to 300 bytes each): I can easily link 60 to 100+ compressed Nametables in 32 KB PRG ROM using vram_unrle().

Suggested Memory Budget Breakdown in 32 KB PRG ROM:

  • C Engine & Game Logic ~10 KB
  • neslib Library & Runtime ~2 KB
  • Audio Engine & SFX (FamiTone2) ~3 KB
  • Available Space for Backgrounds ~17 KB
  • Max Nametable Capacity:
    • Uncompressed ~17 Full Screens
    • *RLE Compressed Allocation ~60 to 100+ Screens

*An RLE-Compressed Nametable is a background screen layout that has been processed using Run-Length Encoding (RLE) to significantly reduce its size in PRG ROM.Instead of storing all 1,024 individual tile bytes for a full $32 \times 30$ grid, RLE compresses repeated identical tiles (like blank sky, floor blocks, or solid walls) into compact sequence commands.

Uncompressed (16 bytes):
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $4A, $4B, $00, $00, $00, $00

RLE Compressed (6 bytes):
[10x $00], [1x $4A], [1x $4B], [4x $00]

Display 1 nametable as the background:

//#link "chr_generic.s"
//#link "nametable.s"

#include <nes.h>
#include "neslib.h"


// Declare external assembly symbol exported in nametable.s
extern const unsigned char nametable_0[];

// Sample palette (Background palette 0)
const unsigned char palette[16] = {
    0x0f, 0x00, 0x10, 0x30, // Black background, Dark Gray, Light Gray, White
    0x0f, 0x00, 0x10, 0x30,
    0x0f, 0x00, 0x10, 0x30,
    0x0f, 0x00, 0x10, 0x30
};

void load_attributes_separately(const unsigned char *tiles, const unsigned char *attributes) {
    // 1. Write tile bytes
    vram_adr(0x2000);
    vram_write(tiles, 960);

    // 2. Write attribute bytes to $23C0 (Nametable 0 attribute offset)
    vram_adr(0x23C0);
    vram_write(attributes, 64);
}

void main(void) {
    bank_bg(0);  // Backgrounds from $0000 (Font/Tiles)
    bank_spr(1); // Sprites from $1000 (Player)
    // Disable rendering while writing to PPU memory
    ppu_off();

    // Load background color palette
    pal_bg(palette);

    // Set PPU address to Nametable 0 start ($2000)
    vram_adr(0x2000);

    // Write the full 960-byte nametable array from nametable.s
    // (32 rows x 30 columns = 960 bytes)
    vram_write(nametable_0, 960);

    // Reset scroll position
    scroll(0, 0);

    // Enable rendering
    ppu_on_all();

    // Infinite loop to keep rendering active
    while (1) {
        ppu_wait_frame();
    }
}

Posted in 8-Bit, games

Post navigation

8bitworkshop Notes – Player Running and Jumping
8bitworkshop Notes – Include binary files

Recent Posts

  • 8bitworkshop Notes – Include binary files
  • 8bitworkshop Notes – Display an external Nametable V1
  • 8bitworkshop Notes – Player Running and Jumping
  • Native Web Speech API
  • AI: You are _____ correct.

Archives

Proudly powered by WordPress | Theme: MiniZen by Martin Stehle.