ca65 list of structs example
Posted: Sun Dec 10, 2023 6:32 pm
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:
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:
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.
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