Page 1 of 1

ca65 list of structs example

Posted: Sun Dec 10, 2023 6:32 pm
by NSkimN8r
As a C++ programmer, I've been learning assembly on the C64. Part of my goal is to establish some patterns for readable, maintainable code. Macros are the obvious choice here, but ca65 introduces structs. After a conversation on the X16 discord, I feel like I have my head around how to use them properly. I created this example to highlight a use case.

The struct components are just offsets from the start of the struct. If the size of the struct is less than 255, we can use the y register as an indexer for a pointer in the zero page.

The gist of this example is that you can set the pointer of an instance in the zero page ($02) and then index the struct members (ie Vector3::_X) in the y register (lda (r0l),y) .

Short Example:

Code: Select all

; fetch the Z axis
ldy #Vector3::_Z
lda ($02),y
   ; do stuff to it
   ;...
; store back in
sta ($02),y

A list of vectors in contiguous memory lets us iterate over the list using the size of the vector3 struct as a stride. A pseudo code version of this would be:
foreach vec in ListOfVects: vec = vec + Vec3(2, 14, 200)

Iterating over an array of structs example:

Code: Select all

; r0 is the zero page address low / high bytes
.define r0l  $02
.define r0h  $03

.struct Vector3
    _X .byte 
    _Y .byte
    _Z .byte
.endstruct

.DEFINE NUM_VECS 10

.struct ListOfVecs
    .byte NUM_VECS * .sizeof(Vector3)
.endstruct

.macro Vec3_add_axis Axis, Value
    ldy #Axis
    lda (r0l),y
    clc 
    adc #Value
    sta (r0l),y
.endmacro

.macro Vec3_add nX, nY, nZ
    Vec3_add_axis Vector3::_X, nX
    Vec3_add_axis Vector3::_Y, nY
    Vec3_add_axis Vector3::_Z, nZ
.endmacro

; allocate the list 
Vlist: .tag ListOfVecs

FunWithStructs:

    ; foreach vec in ListOfVects:
    ;   vec = vec + Vec3(2, 14, 200)

    ; set the pointer: r0 = &Vlist
    lda #<Vlist
    sta r0l 
    lda #>Vlist
    sta r0h 

    ldx #NUM_VECS
foreach:    

    Vec3_add 2, 14, 200

    ; advance the pointer: r0 += sizeof(Vec3)
    clc
    lda r0l
    adc #.sizeof(Vector3) 
    sta r0l 
    lda r0h  ; add the carry
    adc #$00 
    sta r0h

    ; Next
    dex
    bne foreach 

    rts
It would have been nice to have an example of this when I was first starting to use data structures. I hope this helps someone else.