Quantcast
Channel: nesdev.org
Viewing all articles
Browse latest Browse all 785

Thoughts on Expressing Dynamic Indices?

$
0
0
I'm wondering if anyone has any advice on effectively defining indices that map into multiple tables.

As an example, Vs Super Mario Bros. stores several bits of PPU description data in the second CHR bank and loads these in by calling a subroutine with an index to the desired chunk in y. This index is then used to load in the low and high bytes of the address from separate tables, sorta like this (example, not verbatim):

Code:

addr_a = $1EA0addr_b = $1A00addr_c = $1A80addrs_lo:addrs_lo_a:    .byte <addr_aaddrs_lo_b:    .byte <addr_baddrs_lo_c:    .byte <addr_c    addrs_hi:addrs_hi_a:    .byte >addr_aaddrs_hi_b:    .byte >addr_baddrs_hi_c:    .byte >addr_c    loader:    lda addrs_hi, y    sta PPU_VRAM_AR    lda addrs_lo, y    sta PPU_VRAM_AR
Well, I have then an enum supporting calling like:

Code:

    .enum vs_char2_maps        map_a        pal_b        map_c    .endenum        ldy #vs_char2_maps::pal_b    jsr loader
What I want to do is make it so the enum members are defined in terms of the actual indices in the tables. However, defining say, pal_b, as <(addrs_lo_b-addrs_lo), the indices would automatically update if I go adding a new address to the beginning of both tables. Say I'm a careless idiot and only add a new high byte for an address and not a low. I've now got a weird bug where y indexes a different member of the two tables.

Is there a good way in situations like this to derive some sort of "aggregate" index that considers the positions of related elements in different tables effectively?

The best I've landed on (but haven't implemented yet) is to indeed only use one table for generating indices, but then use ca65's assertions to instead generate warnings when the matching parts across tables aren't found at the same indices. In the end, the goal is to be able to painlessly add new members to these sorts of "split up" tables and have the indices reshuffle automatically based on the real position in code rather than a disconnected enum that has to be modified separately. There is a lot of this in SMB, storing the low and high bytes of addresses in separate tables rather than as words in a single table, so a solution to this sort of thing would certainly help make multiple areas more resilient to change. Another prominent example is the actor engine, which has one table for init routines and another for exec routines, both indexed by the "ID" of the actor. Tracking the positions of entries in the init table means the index is decoupled from the exec order and vice versa.

One thing that could help the address hi/lo table situation at least is if ca65 has some way to define that specific data structure in terms of single word entries and have all the low bytes in a list emitted before the high ones and vice versa...but I don't think such a directive exists, and that doesn't solve the scenario like actors where you have multiple completely separate tables expecting the same indexing.

I appreciate anyone's thoughts on best practices here.

Statistics: Posted by segaloco — Sat Aug 24, 2024 8:26 am — Replies 2 — Views 210



Viewing all articles
Browse latest Browse all 785

Trending Articles