ca65 related question... possibly pertaining to a macro

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

Post Reply
Roth
Posts: 400
Joined: Wed Aug 03, 2005 3:15 pm
Contact:

ca65 related question... possibly pertaining to a macro

Post by Roth »

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?
lidnariq
Posts: 10677
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: ca65 related question... possibly pertaining to a macro

Post by lidnariq »

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:

Code: Select all

mystruct: .byte 2 4 5 7 8
endofmystruct:

mystructlength = endofmystruct - mystruct
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: ca65 related question... possibly pertaining to a macro

Post by tokumaru »

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:

Code: Select all

	LDX #(EndLabel - StartLabel)
Loop:
	;ACCESS TABLE HERE
	DEX
	BNE Loop
I'm not very familiar with CA65 though, so someone else might have a solution more suited for it.
User avatar
rainwarrior
Posts: 8062
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: ca65 related question... possibly pertaining to a macro

Post by rainwarrior »

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 = * - mystruct
Roth
Posts: 400
Joined: Wed Aug 03, 2005 3:15 pm
Contact:

Re: ca65 related question... possibly pertaining to a macro

Post by Roth »

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:

Code: Select all

	cpx #(tele_y - tele_floor)
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.
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 : )

Thanks guys, this was really helpful!
User avatar
Movax12
Posts: 529
Joined: Sun Jan 02, 2011 11:50 am

Re: ca65 related question... possibly pertaining to a macro

Post by Movax12 »

Syntax should be as:

Code: Select all

mystruct: .byte 2, 4, 5, 7, 8
And with ca65, you can use .sizeof() instead of label math, example: (loop from start to #0 as suggested):

Code: Select all


  LDX #(.sizeof(mystruct)-1)
  :
  ; do stuff
  DEX
  BPL :-

edit:Fix bad code :)
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: ca65 related question... possibly pertaining to a macro

Post by tokumaru »

Movax12 wrote:And with ca65, you can use .sizeof() instead of label math
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?
User avatar
Movax12
Posts: 529
Joined: Sun Jan 02, 2011 11:50 am

Re: ca65 related question... possibly pertaining to a macro

Post by Movax12 »

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):

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))
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: ca65 related question... possibly pertaining to a macro

Post by tepples »

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
Post Reply