Pointer table: Difference between revisions

From NESdev Wiki
Jump to navigationJump to search
(Code pointer tables)
No edit summary
Line 1: Line 1:
==Preface==
A pointer table is any area of memory that is filled with the addresses of other specific areas of memory. When we store the address of an area of memory this is referred to as a "pointer", because it "points to" that area of memory. This article demonstrates how a pointer table can be used to access variable-length data.
A pointer table is any area of memory that is filled with the addresses of other specific areas of memory. When we store the address of an area of memory this is referred to as a "pointer", because it "points to" that area of memory. This article demonstrates how a pointer table can be used to access variable-length data.
__TOC__


==The problem==
==The problem==
Line 19: Line 19:
Finally the length of the data must be stored so we know how much data to copy. We use the assembler's ability to perform math on labels for this. Not all assemblers support this however.
Finally the length of the data must be stored so we know how much data to copy. We use the assembler's ability to perform math on labels for this. Not all assemblers support this however.


; Pointer table for our frames
<source lang="6502tasm">
frame_pointers_lo:
; Pointer table for our frames
    .byte <_frame01, <_frame02, <_frame03, <_frame04
frame_pointers_lo:
frame_pointers_hi:
    .byte <_frame01, <_frame02, <_frame03, <_frame04
    .byte >_frame01, >_frame02, >_frame03, >_frame04
frame_pointers_hi:
    .byte >_frame01, >_frame02, >_frame03, >_frame04
; Data lengths
 
frame_data_lengths:
; Data lengths
    .byte _frame02 - _frame01, _frame03 - _frame02
frame_data_lengths:
    .byte _frame04 - _frame03, _frame_end - _frame04
    .byte _frame02 - _frame01, _frame03 - _frame02
    .byte _frame04 - _frame03, _frame_end - _frame04
; Frame Data
 
_frame01:
; Frame Data
    .byte "Some random data"
_frame01:
_frame02:
    .byte "Some random data"
    .byte "related to the frames"
_frame02:
_frame03:
    .byte "related to the frames"
    .byte "that is of variable"
_frame03:
_frame04:
    .byte "that is of variable"
    .byte "length", $00
_frame04:
_frame_end:
    .byte "length", $00
_frame_end:
</source>


==Using the pointer table==
==Using the pointer table==
Line 47: Line 49:
Example:
Example:


; Routine to load the sprite frame definition for a given frame.
<source lang="6502tasm">
; Y = The frame to load data for
; Routine to load the sprite frame definition for a given frame.
.proc load_frame_data
; Y = The frame to load data for
    ; Local variables
.proc load_frame_data
    .segment "zp"
    ; Local variables
        frame_pointer: .word 0 ; Our zero-page pointer for the frame data.
    .segment "zp"
    .segment "ram"
        frame_pointer: .word 0 ; Our zero-page pointer for the frame data.
        frame_length: .byte 0 ; The number of bytes in our frame data
    .segment "ram"
        frame_length: .byte 0 ; The number of bytes in our frame data
    ; Routine Start
 
    .segment "prg"
    ; Routine Start
    .segment "prg"
    ; Frame pointer low byte
 
    lda frame_pointers_lo,y
    ; Frame pointer low byte
    sta frame_pointer
    lda frame_pointers_lo,y
    sta frame_pointer
    ; Frame pointer high byte
 
    lda frame_pointers_hi,y
    ; Frame pointer high byte
    sta frame_pointer
    lda frame_pointers_hi,y
    sta frame_pointer
    ; Iterate over each byte
 
    lda frame_data_lengths,y
    ; Iterate over each byte
    sta frame_length
    lda frame_data_lengths,y
    ldy #0
    sta frame_length
data_loop:
    ldy #0
    lda (frame_pointer),y
data_loop:
    ; Do something with the frame byte in A, like transform it into OAM data
    lda (frame_pointer),y
    iny
    ; Do something with the frame byte in A, like transform it into OAM data
    cpy frame_length
    iny
    bne data_loop
    cpy frame_length
    bne data_loop
    rts
 
.endproc
    rts
.endproc
</source>


== Code pointer tables ==
== Code pointer tables ==
Code is another form of data, and subroutines can be accessed through pointer tables as well.
Code is another form of data, and subroutines can be accessed through pointer tables as well.
See [[Jump table]].
See [[Jump table]].

Revision as of 09:29, 24 August 2013

Preface

A pointer table is any area of memory that is filled with the addresses of other specific areas of memory. When we store the address of an area of memory this is referred to as a "pointer", because it "points to" that area of memory. This article demonstrates how a pointer table can be used to access variable-length data.

The problem

When we have multiple pieces of variable-length data, such as complex sprite meta-tile definitions, we need to be able to access those pieces of data using some index number. This allows us to uniquely identify each meta-tile compactly. This also allows us to go to the previous or next meta-tile without having to know anything about the underlying data.

Organization of the data file

Typically the pointer table and the data it points to is defined together within an assembly file. This allows us to easily change the data and re-arrange the pointer table as needed.

Tip: If you prefer to keep this data in a external file format such as XML and process it with a custom tool, have the tool generate the assembly file described below rather than a binary format. This is often much easier to debug and address.

In our sprite meta-tile example we might have several sprite frame definitions at the bottom of the file. These definitions will use the assembler's BYTE directive (typically .db or .byte) to declare the data. Each frame's data will be preceded by a unique label that we will reference from within the pointer table.

The pointer table usually comes at the top of the file. The pointer table will use the assembler's BYTE directive again to store the high and low bytes of our frame labels in two different tables.

Finally the length of the data must be stored so we know how much data to copy. We use the assembler's ability to perform math on labels for this. Not all assemblers support this however.

<source lang="6502tasm">

Pointer table for our frames

frame_pointers_lo:

   .byte <_frame01, <_frame02, <_frame03, <_frame04

frame_pointers_hi:

   .byte >_frame01, >_frame02, >_frame03, >_frame04
Data lengths

frame_data_lengths:

   .byte _frame02 - _frame01, _frame03 - _frame02
   .byte _frame04 - _frame03, _frame_end - _frame04
Frame Data

_frame01:

   .byte "Some random data"

_frame02:

   .byte "related to the frames"

_frame03:

   .byte "that is of variable"

_frame04:

   .byte "length", $00

_frame_end: </source>

Using the pointer table

To use the pointer table to access our data we will need to use the frame index as an offset into the pointer table. We then load this pointer into a zero-page variable so we can use it to load data.

Example:

<source lang="6502tasm">

Routine to load the sprite frame definition for a given frame.
Y = The frame to load data for

.proc load_frame_data

   ; Local variables
   .segment "zp"
       frame_pointer: .word 0 ; Our zero-page pointer for the frame data.
   .segment "ram"
       frame_length: .byte 0 ; The number of bytes in our frame data
   ; Routine Start
   .segment "prg"
   ; Frame pointer low byte
   lda frame_pointers_lo,y
   sta frame_pointer
   ; Frame pointer high byte
   lda frame_pointers_hi,y
   sta frame_pointer
   ; Iterate over each byte
   lda frame_data_lengths,y
   sta frame_length
   ldy #0

data_loop:

   lda (frame_pointer),y
   ; Do something with the frame byte in A, like transform it into OAM data
   iny
   cpy frame_length
   bne data_loop
   rts

.endproc </source>

Code pointer tables

Code is another form of data, and subroutines can be accessed through pointer tables as well. See Jump table.