Jump to content

2 Beginner questions about assembly programming using CC65


JvH
 Share

Recommended Posts

Hello!

During the last couple of days I've been converting a CBM prg Studio ML project (target: Commodore 64) to CX16. I'm using the cc65 suite to assemble my code.
At this moment there are 2 things about cc65 that I don't really understand.

1) The CONDES section in cx16-asm.cfg
From what I understand, this is mostly meant for C development. Each module can 'export' pointers to their constructor and destructor code, so that this code is called before/after main() is executed. I am, however, only using assembly. So my questions are:
* What purpose does it serve when you're using only assembly? It's in cx16-asm.cfg after all, so it must be there for a reason right?
* The constructor entry refers to a segment (ONCE) that's not even present in the configuration. Is this created on-the-fly? If so, in which memory segment does it get added?
* What is the interruptor entry for?

2) Working with multiple files
In hopes of increasing readability, I split my project into multiple files. I use .include to refer to other files, which just inserts the file contents at the position of the .include. I'm really not sure if this is the way to go. Yes, I don't have to .import and  .export and still have access to all identifiers in my code. But the downside is that you really have to be careful about including files twice or including them in the wrong order.
Are there some developers with experience in cc65 who can give me some hints and tips on managing multi-file cc65 projects?

Thanks in advance for your replies.

Link to comment
Share on other sites

  1. A lot of the stuff in the cc65 configuration files isn't necessary for assembly. While this extra section might enable some advanced features, I have never used any of them.
  2. I use multiple separately assembled files, which are linked together to build the program. While this does require me to import and export symbols, I am thinking of writing something similar to a C header file for future projects.
Link to comment
Share on other sites

Hi Elektron72,

Thanks for your very quick reply!

Quote

A lot of the stuff in the cc65 configuration files isn't necessary for assembly. While this extra section might enable some advanced features, I have never used any of them.

Indeed, I don't think I'll need this anytime soon. Still curious why they included it in a config that is specific to assembly. Maybe when you assemble your code into a module and link that into a C project.

Quote

I use multiple separately assembled files, which are linked together to build the program. While this does require me to import and export symbols, I am thinking of writing something similar to a C header file for future projects.

Could you explain to me how that works? Is it a matter of exporting the symbols you're going to need externally, assembling your code into a .o file (without the BASIC header of course) and then including that .o file when calling cl65?

Link to comment
Share on other sites

2 hours ago, JvH said:

Could you explain to me how that works? Is it a matter of exporting the symbols you're going to need externally, assembling your code into a .o file (without the BASIC header of course) and then including that .o file when calling cl65?

That's exactly it, yes.

  • To declare a symbol that needs to be exported, your use the `.export` statement.
  • And similarly, to declare a symbol that needs to be imported from another module, you use the `.import` statement.
  • ca65 also has the `.global` statement, which I find extremely convenient because it changes meaning based on whether or not a symbol is defined elsewhere within a module.

So, for instance, I have a "math.inc" file that contains a bunch of .global statements for my math procedures, like so:

	.global math_init
	.global cos_8
	.global sin_8
	.global mul_8
	

These procedures are all implemented in "math.asm", so I make sure that math.asm includes that inc file, and I make sure any other source file that needs to use my math procedures also includes math.inc, such as my "splash.asm" that does my little demo splash screen intro.

By including math.inc into math.asm, ca65 will see the symbols defined and interpret the globals to mean that those symbols need to be exported. By including math.inc into splash.asm, ca65 will see that the symbols were never defined and interpret the globals to mean that those symbols need to be imported.

Then I compile the .asm files into .o files individually with ca65, then link them together into a final executable with cl65:

	ca65 --cpu 65C02 math.asm -o math.o
	ca65 --cpu 65C02 splash.asm -o splash.o
	cl65 --target cx16 math.o math.o -o SPLASH.PRG
	

See also: https://www.cc65.org/doc/ca65-11.html

Edited by StephenHorn
  • Like 1
  • Thanks 2
Link to comment
Share on other sites

Hello Stephen, thanks for your answer.

Let me check if I understand this correctly.
* You put all global symbols from math.asm in a separate math.inc file, and you include that file (with .include) in math.asm
* Assembling math.asm yields math.o, which contains the ML code + the used symbols
* In splash.asm you .include math.inc, but when linking you refer to math.o
Am I correct?

Another question that comes to mind:
Suppose you have a math.asm with cos, sin and tan functions. Let's assume, for the sake of argument, that those functions don't share any code.
Now if you include math.inc in your program only to use the sine function, I assume math.asm will still be added to the prg file in its entirety. Is that correct?

EDIT: now that I come to think of it, I suppose that is what .ifref could be used for...
EDIT2: oh right, that's exactly what the documentation says 😄

Edited by JvH
  • Like 1
Link to comment
Share on other sites

1 hour ago, JvH said:

Hello Stephen, thanks for your answer.

Let me check if I understand this correctly.
* You put all global symbols from math.asm in a separate math.inc file, and you include that file (with .include) in math.asm
* Assembling math.asm yields math.o, which contains the ML code + the used symbols
* In splash.asm you .include math.inc, but when linking you refer to math.o
Am I correct?

Another question that comes to mind:
Suppose you have a math.asm with cos, sin and tan functions. Let's assume, for the sake of argument, that those functions don't share any code.
Now if you include math.inc in your program only to use the sine function, I assume math.asm will still be added to the prg file in its entirety. Is that correct?

EDIT: now that I come to think of it, I suppose that is what .ifref could be used for...
EDIT2: oh right, that's exactly what the documentation says 😄

For the most part, this is all correct.

Technically, assembling math.asm yields math.o, which contains an intermediate representation of the ML + used symbols. This might be an academic difference, but I suppose the important thing to note is that it isn't necessarily the final machine language, even with annotations, because the assembler won't necessarily know a bunch of important details, such as the values of external symbols, or even the final location of the code that's been assembled.

All of that information is reconciled by the linker, which is given all of the necessary modules (the .o files), in order to figure out all the symbols and organize them into their final locations.

Link to comment
Share on other sites

I'm trying to create an object file containing VERA-related subroutines, but I can't get it working.

I've got vera.inc, which contains (among other things):
.global clearScreen

I have vera.asm:
.include "vera.inc"
...

.ifref clearScreen
.proc clearScreen
...
.endproc
.endif

In my main program I have:
.include "vera.inc"
...
jsr clearScreen

I get the error:
"Unresolved external 'clearScreen' referenced in:
  program.asm(12)
ld65: Error: 1 unresolved external(s) found - cannot create output file"

If I remove the .ifref ... .endif lines it works, but I'd really like to include only the stuff from vera.o that I actually need. What am I doing wrong?

Edited by JvH
Link to comment
Share on other sites

If I understand the documentation correctly (https://www.cc65.org/doc/ca65-11.html#ss11.58), .ifref only returns true if something has referenced the name before it reaches the .ifref 

In your case I am guessing you are including vera.inc in the beginning of vera.asm hence clearScreen has not been referenced yet when the compiler goes through the vera.inc source.

Link to comment
Share on other sites

Indeed, that's what the documentation says. So I've already tried including vera.inc at the end of my main program's asm file. Still, it gives the same error. I also tried switching vera.o and program.asm in the call to cl65, but that didn't help either.

Link to comment
Share on other sites

I think what's going on is that the ".ifref" is only being considered by the assembler, not the linker, and ".global" doesn't count as a reference. So when you call ca65 with vera.asm, it sees the ".ifref", observes that vera.asm hasn't actually used that procedure anywhere by that point in the file, and then discards it because of your ".ifref". The fix, then, is to remove the ".ifref" and just understand that your clearScreen function will always be included in your lib.

Or, if you wanted to control whether clearScreen is included in a build, you can't do it automatically, you'd have to define and then use .ifdef or plain .if comparisons:

	vera.inc:
	.define INCLUDE_CLEARSCREEN 1
	...
	.if INCLUDE_CLEARSCREEN = 1
	.global clearScreen
	.endif
	 
	vera.asm
	.include "vera.inc"
	.if INCLUDE_CLEARSCREEN = 1
	.proc clearScreen
	...
	.endproc
	.endif
	 
	main.asm
	.include "vera.inc"
	...
	jsr clearScreen
	

Unfortunately, from a quick look it does not appear that cl65 supports any link-time optimization, such as discarding unused segments of code.

  • Like 1
Link to comment
Share on other sites

3 hours ago, JvH said:

That's a bummer, but yes I expect that's actually what's happening here.

Did you bother to solve this in your demo, or did you just include your entire graphics library?

I simply included my entire graphics library. But I should add that my demo is using effectively the entirety of my graphics library - that's initially why I wrote the lib, after all. Or rather, I did not implement functions in the lib on the basis of theoretical wants, I needed these functions first.

Link to comment
Share on other sites

20 hours ago, StephenHorn said:

it does not appear that cl65 supports any link-time optimization

Heh, no tool is perfect:   I'm using the 64tass assembler, and it does exclude unused blocks/procedures.  However I'm now pondering how to make it not do that because I was thinking about ways to create a library program that includes everything you assemble even though it is not called... 🙂

Link to comment
Share on other sites

1 minute ago, desertfish said:

Heh, no tool is perfect:   I'm using the 64tass assembler, and it does exclude unused blocks/procedures.  However I'm now pondering how to make it not do that because I was thinking about ways to create a library program that includes everything you assemble even though it is not called... 🙂

In that case I'd highly recommend cc65 😉

I have started a discussion about this on cc65's Github page. Maybe that will lead to some new insights.

Link to comment
Share on other sites

Finally, I figured it all out. Thanks guys for your help.

Assembling library method into separate object files and using ar65 to put them into lib files does exactly what I'm aiming for: only assembling the code that I actually use in my main program.

I also realized what I was doing wrong with the .ifref approach. For now I directly include the asm files that make up my main program. I did have a vera.inc file containg my globals (including the clearScreen symbol) and vera.asm that contained the clearScreen method itself.
In my main program though I only included vera.inc, so the clearScreen symbol+implementation couldn't be found.

Another lesson learned 🙂

  • Like 2
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...

Important Information

Please review our Terms of Use