ca65 related question... possibly pertaining to a macro
Moderator: Moderators
ca65 related question... possibly pertaining to a macro
I remember when I was learning some other programming languages that I've since forgotten, there would be something along the lines of the "length" of a variable or some such. Like, string.length or thereabouts. Well, I was wondering if there was something I can do similar to that with a macro in ca65. An example of what I need is this...
I have a table of bytes. The table of bytes gets read through and tested every frame. At the end of the routine that tests these bytes, I have a simple INX/CPX #$xx to see if all the bytes have been read or not. The slight inconvenience I have is that everytime I add some bytes to the end of the table, I have to manually update what the 'X' register is compared to. I was wondering if there was a way to make a macro or something like that which I could plug in, in place of #$xx, that had a parameter of the name of the table. So when the assembler builds the file, it takes the "table.length" and places the proper number where the CPX #$xx is. Is something like this possible?
I have a table of bytes. The table of bytes gets read through and tested every frame. At the end of the routine that tests these bytes, I have a simple INX/CPX #$xx to see if all the bytes have been read or not. The slight inconvenience I have is that everytime I add some bytes to the end of the table, I have to manually update what the 'X' register is compared to. I was wondering if there was a way to make a macro or something like that which I could plug in, in place of #$xx, that had a parameter of the name of the table. So when the assembler builds the file, it takes the "table.length" and places the proper number where the CPX #$xx is. Is something like this possible?
Re: ca65 related question... possibly pertaining to a macro
A standard thing I've done is put a label at the end. This relies on assemblers always putting things in-order.
This won't work with tools that fuzz the order of arrays to uncover bugs, but most assemblers don't do that.
For example, in ca65:
This won't work with tools that fuzz the order of arrays to uncover bugs, but most assemblers don't do that.
For example, in ca65:
Code: Select all
mystruct: .byte 2 4 5 7 8
endofmystruct:
mystructlength = endofmystruct - mystruct
Re: ca65 related question... possibly pertaining to a macro
The first thing I suggest is scanning the table backwards (if that doesn't break any of your logic), since you can get rid of the CPX and just use the N flag (0-based index, maximum of 128 elements) or the Z flag (1-based index, maximum of 256 elements) to detect the end of the loop, making it faster.
You'd still need to initialize X to the length of the table to begin the loop though, so the question remains. I don't think the assembler has a way to know where the table ends unless you put another label there, in which case you can do (EndLabel - StartLabel) to get the length of the table:
I'm not very familiar with CA65 though, so someone else might have a solution more suited for it.
You'd still need to initialize X to the length of the table to begin the loop though, so the question remains. I don't think the assembler has a way to know where the table ends unless you put another label there, in which case you can do (EndLabel - StartLabel) to get the length of the table:
Code: Select all
LDX #(EndLabel - StartLabel)
Loop:
;ACCESS TABLE HERE
DEX
BNE Loop- rainwarrior
- Posts: 8062
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: ca65 related question... possibly pertaining to a macro
As a slight simplification of lidnariq's suggestion, ca65 has the * symbol which is the program counter position known at link time, letting you do this:
Code: Select all
mystruct: .byte 2 4 5 7 8
mystructlength = * - mystructRe: ca65 related question... possibly pertaining to a macro
Very cool!
I happen to have another table that I always have right below it, as it is something that gets accessed along with that routine, so I only have to use that second table with it:
Thanks guys, this was really helpful!
I happen to have another table that I always have right below it, as it is something that gets accessed along with that routine, so I only have to use that second table with it:
Code: Select all
cpx #(tele_y - tele_floor)
I use that technique when I'm working on some of my 1k games to save a byte here and there, but I find it to be more confusing overall. When I'm doing a regular full blown project, I just stick with the CPX method. Good suggestion of course, though : )tokumaru wrote:The first thing I suggest is scanning the table backwards (if that doesn't break any of your logic), since you can get rid of the CPX and just use the N flag (0-based index, maximum of 128 elements) or the Z flag (1-based index, maximum of 256 elements) to detect the end of the loop, making it faster.
Thanks guys, this was really helpful!
Re: ca65 related question... possibly pertaining to a macro
Syntax should be as:
And with ca65, you can use .sizeof() instead of label math, example: (loop from start to #0 as suggested):
edit:Fix bad code 
Code: Select all
mystruct: .byte 2, 4, 5, 7, 8
Code: Select all
LDX #(.sizeof(mystruct)-1)
:
; do stuff
DEX
BPL :-
Re: ca65 related question... possibly pertaining to a macro
How does it know where the table ends, though? If I put a second .byte statement on the next line, does that also count as part of the table? What if I .incbin a file?Movax12 wrote:And with ca65, you can use .sizeof() instead of label math
Re: ca65 related question... possibly pertaining to a macro
For .incbin I am not sure, but for a label, it seems to be based on EOL.
I know you can also get the size of a .scope (or a .proc):
I know you can also get the size of a .scope (or a .proc):
Code: Select all
.scope DATA
mylabel: .byte 12, 23, 45, 45, 67, ABh
.byte 12, 23, 45, 45, 67, ABh
.endscope
.out .sprintf("The size of DATA is: %d" .sizeof(DATA))
Re: ca65 related question... possibly pertaining to a macro
If you have a bunch of different items each with different lengths, you can make a table of their lengths just as you make a table of pointers to the start. Or you can do it the C way: reserve one byte value for "end of data" and end the loop once you hit that byte.
Code: Select all
page_ptrs:
.addr page1_txt, page2_txt, page3_txt
num_pages = (* - page_ptrs) / 2
page1_txt:
.incbin "instructions1.txt"
.byte $00
page2_txt:
.incbin "instructions2.txt"
.byte $00