Jump to content

CC65 and Making Your Own Library


rje
 Share

Recommended Posts

I now have code that I want to share between my projects -- sprite and PSG code mainly, but there's other stuff too.

I've never created a library ... or I can't remember doing it, anyway.  Can anyone point me to the right place to learn how?

Is it done exactly the same as "normal" C code?  

I'll assume that it is, and go to Stacktrace.  If someone has further enlightenment, please let me know.

 

Link to comment
Share on other sites

I'm 99.9999% sure these would be statically linked libraries.  After all, I seriously doubt 8-bit machines will dynamically load object files.

If I remember and read right, I can use -c to create the object files.  I suspect my header has to declare accessible functions with extern.

Then, if I stored my object files in a central location, I can use -L with the compiler to specify a library path.

Or, maybe, use -I for the include library path?

In "normal" C you have different switches used by the linker and loader.

 

Time for more reading.

 

Edited by rje
Link to comment
Share on other sites

And I note that AR65 is an archiver of object files... which sounds just like a Library.  So then:

 

cc65 -c file1.c ...

...creates object files.  Then:

ar65 r mylib.lib file1.o ...

Adds the object files to mylib.lib (and creates it if needed).

 

When using mylib.lib, I guess cc65 needs to know the path to (a) the headers, and (b) the library.  So that would look like this:

 

cl65 -I include_files_dir -L path_to_libraries [and all the rest of the command line stuff]

 

 

Edited by rje
Link to comment
Share on other sites

On 11/15/2021 at 8:55 AM, rje said:

I'm 99.9999% sure these would be statically linked libraries.  After all, I seriously doubt 8-bit machines will dynamically load object files.

While it might not have a formal method called dynamic linking, that's more or less how program use the kernal. A jump table of function entry points. Not unlike how GEOS supported multiple printers and input devices: load a module to a well known address and use its jump table.

Modern dynamic linking allows for more complexity, but at its heart it is the same thing.

  • Like 1
Link to comment
Share on other sites

I think this is going to turn into a major reorganization of my code, and potentially a reworking of my Makefiles.

Although I can get away with a simple shell script for now which builds the library and creates the /include directory.

 

But... I see the usefulness of splitting my utility code into multiple libraries.  Eeek.

Link to comment
Share on other sites

On 11/15/2021 at 10:01 AM, rje said:

When using mylib.lib, I guess cc65 needs to know the path to (a) the headers, and (b) the library. 

Technically, the library doesn't have any headers or need them. The headers are for the benefit of any projects that want to use the library. You just write that as a .h file and #include the .h file to make it easier for your programs, so they don't have to know all of the right ways to declare the goodies found in the library. 😉

 

  • Thanks 1
Link to comment
Share on other sites

And I can say that for X16 - if you can write your library in pure assembly, it will run much faster than if you write it in C. (obviously)

I'm getting close to the point in my zsound.lib project where I'm going to make some C stubs to translate C's function calls into what my routines ACTUALLY need to run. (basically, pull stuff from the stack, put them into whatever ZP / regs I want, and then JSR the real routine). That's why it's useful for C space to use _symbol.

I can export playmusic and _playmusic
_playmusic will just pull the C parameters and call playmusic

  • Thanks 1
Link to comment
Share on other sites

On 11/15/2021 at 11:16 AM, ZeroByte said:

And I can say that for X16 - if you can write your library in pure assembly, it will run much faster than if you write it in C. (obviously)

I'm getting close to the point in my zsound.lib project where I'm going to make some C stubs to translate C's function calls into what my routines ACTUALLY need to run. (basically, pull stuff from the stack, put them into whatever ZP / regs I want, and then JSR the real routine). That's why it's useful for C space to use _symbol.

I can export playmusic and _playmusic
_playmusic will just pull the C parameters and call playmusic

I'm interested -- do you discuss this somewhere on this site?

And, regarding pure assembly (inline?) -- I'm also interested.

Link to comment
Share on other sites

On 11/15/2021 at 5:50 PM, rje said:

I'm interested -- do you discuss this somewhere on this site?

And, regarding pure assembly (inline?) -- I'm also interested.

I haven't unveiled zsound yet. It's a set of tools and a library which work together to create and play back music and SFX in "standardized" formats. These formats are designed as pre-rendered streams of register writes for the YM2151 and PSG chips (PCM is intended as well but I haven't gotten to that yet). The goals are: fast, lightweight playback engine, and well-defined data format that anyone can create compatible tools for both on and off platform. I'll be sharing more details fairly soon.

As for pure assembly, consider a simple example utility function clear_screen();

the prototype in the .h file is just "extern void clear_screen();"

The .asm file would be this:
.include "x16.inc"
.export "_clear_screen"

.segment "CODE"

.proc _clear_screen: near
  VERA_SET_ADDR $0000, 2 ; set VERA data0 to point at VRAM 0000, and use step=2
  lda #32 ; blank space character
  ldx #0
  ldy #$20 ; the default screen is 128x64 - which is the same as 256*32 ($100 * $20)
next:
  sta VERA_data0
  dex
  bne next
  dey
  bne next
  rts
.endproc

The ASM file may contain as many routines and variable definitions as you like, but remember that ld65 links code in "units" of .o files - that is, if anything at all in a .o file is required, then the entire module will be linked in. Thus, it seems like good practice to put each routine in its own .asm file so that only what's needed gets linked in. So while you could add another routine here that sets the entire screen's color attribute bytes to some value (for example), if a program only uses clear_screen, then it will also get the code for the "Set screen color" routine as well, even if it's never used. You don't have to worry about that with the .h file though. You can make mylib.h contain all of your functions' declarations, but only the .o files necessary will be linked in from your archive.

So now you assemble the .asm file with the -c flag as you mentioned, creating clear_screen.o - which you add to the archive mylib.lib with the command ar65 a mylib.lib clear_screen.o

Assuming mylib.lib and mylib.h are both in places where the compiler and linker can find them, you can include them in your project with #include "mylib.h" in your C sources, and build your programs with the library file included in the list of sources:
cl65 -t cx65 -o MYPROG.PRG main.c input.c output.c mylib.lib

Obviously, you'd want to make this routine accept parameters, such as what the fill character should be. (It can actually just read VERA to know what the current screen RAM location / dimensions to use - this is just a basic example). Unfortunately, I don't know (currently) what steps to use for accepting parameters and sending return values. __fastcall__ makes the rightmost parameter use the X/Y registers as a 16-bit parameter, but beyond that, I'd have to go look at docs and code examples - especially for going into the stack to retrieve parameters.
 

Edited by ZeroByte
  • Like 1
  • Thanks 1
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