Good questions. I've been using cc65 for a while (few years), including the PET, Apple2, C64, and X16 target platforms (with Windows, can't speak to how it handles on other platforms). [ see destinyhunter.org ]
Johan Kårlin wrote: ↑Mon Nov 13, 2023 1:54 pm
1. How stable is the compiler? There are no proper releases, just what seems to be daily builds on sourceforge.net. Is this something to worry about?
Support for float or double was never added. On lemon64.com I ran into a contact that had a branch of cc65 that did include float-type support. There was talk of rolling that into the main baseline, but I've not seen action on it. The specific use case we were doing that solar system modeling, where anything dealing with astronomical modeling ends up with very large numbers. Without getting to sidetracked: there are many situations when one thinks they need floating point, but really don't (even when dealing with currency, there are other ways to re-think a solution {like just work in units of cents, etc.}).
On github there are cc65 folks that will respond to Issues. One of the last Issues I raised is they don't really support the original PET 2001 as a target platform (there are zeropage differences with that systems original ROMs). They recognized the issue, and summarized what fixes would be needed, but the "user base" on that platform is very small I don't think an official fix was merged in. But I was content enough to have it verified there was an issue and not something I was just doing wrong. I wouldn't go demand/requesting "upgrading" or modernizing the C language support that it has.
I don't think I've actually done nested/recursive calls in cc65. That's a "C thing to do" but I generally avoid such solutions and stick with iterative ones. But aside from that, the coverage of C language support seems "pretty stable." You can do loops, functions even with variable number of arguments, records, pointers, inline assembly.
But there can be some confusion on where one gets their cc65 build from. You mentioned sourceforge? I haven't actively looked recently, but those prebuilds could be different than what is offered on github. Not necessarily bad, but just be aware that "someone else's cc65 might not be exactly like yours" kind of stuff can happen.
Quick note while thinking of it: in cx16.cfg (when using the Commander X16 as target), the "baseline" stack reserve may be set at $2000 which can be way more than most people need. So to get more codespace/RAM, one quick easy thing to do is to reduce that down. If you're not calling a lot of functions or they don't have many passed arguments, you could drop it to even under $100.
Johan Kårlin wrote: ↑Mon Nov 13, 2023 1:54 pm
2. The generated BASIC stub is "531 SYS 2061". Is something wrong or why "531"?
I've noticed this also and never really questioned it or had it bother me. Reasonable question at the github Issues or Discussions item, or searching if they already have an answer. Can't recall if they do this same 531 on the other platforms or if this was some arbitrary CX16 decision (or a side effect of how the CX16 has evolved from when CX16 support was originally added into cc65).
Johan Kårlin wrote: ↑Mon Nov 13, 2023 1:54 pm
3. The generated code starts with switching to lower character mode. I can't find a way to avoid this. Is it possible? Of course, I can just switch back, but I think it is worth a question.
On the cc65 I have, I think this is a side effect of bringing in cx16.lib . They'll have their own entry point to do things like parse "command line arguments" and initialize their runtime, which from there then jumps into your actual _main on wherever it ended up placed by the linker. I've not recompiled/built that cx16.lib (I'm not a die hard open-source fanatic; not a bad thing, just some do insist on only running things that they can or have prebuilt themselves and I can appreciate the philosophy of that). I think all the necessary .s files are there to do a build of the cx16.lib (in a libsrc folder). X16 makes it easy to change text modes, so for example in cc65 you can do this:
#define ENABLE_ISO_MODE \
__asm__("lda #$0F"); \
__asm__("jsr $FFD2");
Just find the character code that corresponds to the text mode you prefer. The main issue is really that by the time you get to your _main, you've lost the "original mode" that the user started your program in. There is an address to query what the current text mode or screen mode is, but as you mentioned, the cc65 core has changed/set it by the time you're able to query that. So the elaborate workaround is a pre-loader or modified autoboot.x16 that queries this, stores it somewhere, before loading your main .PRG, etc. Not fun.
But then, it gets a little worse: keyboard scan codes, display codes, and what "character set" the file I/O routines use. Every compile has to deal with this (the "character set"). Loosely we can say cc65 all uses PETSCII and the upper/grx variety. But you may eventually just run into frustrations (like what values to use in case statements while polling keyboard input, versus parsing file input). One could probably write a book on it, and each users use-case may be a little different (relative to keyboards being used, international systems, etc). So it just takes some trial and error to "dial in" what works for you. This could be why the core cc65 switches to that mode, as everything is setup to "just work" with that. So while you can change that behavior, it could have some unexpected ripple effects elsewhere.
NOTE: but bottom line is, eventually for performance reasons, you'll want to learn about "display codes." All the built in C library stuff isn't designed around display codes, so they are inherently slow for that reason. I can share the "library" (not an actual .lib, but just a .h with a bunch of #define macros) that I help to speed navigation and interaction with the text screen (and timers) a bit faster -- but in general I think most developers build up their own tailored equivalent of that. Attached is a simple starter example.
I guess to answer your specific question, short of rebuilding cx16.lib, no I don't think the mode switch can be avoided by a setting or simple .cfg change somewhere.
Johan Kårlin wrote: ↑Mon Nov 13, 2023 1:54 pm
4. I tried to make a hello-world-program with just one line of code, a call to print(). I can run it once without any problems. The second time it crashes and I end up in the monitor. Is this how it should be? Can you just run the compiled programs once?
Yep, same experience here. However, pay attention to your #includes. I've found that if you #include nothing (which then means your _main is basically doing nothing, except maybe a for-loop and simple integer calculations-- maybe a POKE) - in that case, I've found that I can re-run the PRG without issue (i.e. RUN, program "naturally exits", then I can RUN again). So it's not an inherent problem about cc65, but something influenced by one of the #incude's. I can't recall which specific one. The system is sensitive to a few address regions (zero page, kernal reserved, then BASIC itself has a few sensitive addresses). That's a thing of C, various ways to get code executed before your _main entry point (like even just by initializing global variables, it can be an inherit part of your laded .PRG but arranged in a way that blasts over an important system region).
The other thing I've noticed is that you don't have to do a full reboot. CTRL+ALT+RESTORE, then just re-loading your .PRG is often good enough to be able to RUN again. On the hardware, there is one type of reset that you can hear (causes a relay to click), the other is a "soft" reset that doesn't clear/alter as much of the memory (and you won't hear that relay click). The system is still stable enough to at least issue another LOAD.
But anyhow, yes it is an issue - and again it could just be how the CX16 system has evolved since the cx16 target support was initially added into cc65 (which I think it is amazing that cc65 still mostly works with the cx16, but the "startup sequence" probably does need a good dusting off. There may be some clever way to inject some .s to get ran before your _main and maybe save more of the machine state, and have your exit code use that to revert the state. This issue does make convenient utilities difficult to develop.
Johan Kårlin wrote: ↑Mon Nov 13, 2023 1:54 pm
5. I tried to load a file by calling the kernal LOAD. It works fine. If I remove the file, it works too, my code handles the error, but I get a short blinking red line in the upper right corner of the screen. It is not part of the text layer and layer 0 is disabled so it must be something the emulator comes up with on its own? The strange thing is that the same assembly code works in ACME without any red line turning up.
This caught me too. I haven't read through all the other replies so this was probably already answered... The emulator uses this flashing red to simulate the hardware light that is around the reset switch (David once briefly mentioned his preference of changing that light to red on the hardware, as the Lazer3D case chose to use blue lights instead). This was a C64 behavior (where they probably used red), so the disk drive can give status that something didn't work quite right on the last operation. It's a little annoying (in reality) where you might get that stuck flashing for a long time, there is no timeout about it. There is probably some kernal call to clear the last error (probably just a CLOSE command in BASIC), or just issue a correct OPEN (valid filename, etc). There has been a lot of discussion repeated in Discord about the need to check Device 15 for actual OPEN status.
In my XINFO project, I'm at a point of using the cbm.h stuff in cc65 to do cbm_open/read/close for File IO and checking the status - so I can refer to that as an example. But similar to working with the display: for performance, the OPEN KERNAL call is probably the way to go, so most "shops" (independent developers) will probably want to build up their own #define repository to help with those calls. stdio.h and fopen does work relatively fine, but will also be slow and have certain limitations (like filenames limited to 16 characters was one limitation I ran into with it, whereas the cbm.h stuff was not limited {well, probably 255 char limited}).
So your questions are good, and mostly yes: that's just the state of cc65 currently on the cx16. It's not bad, you can quickly develop up some interesting things. But there are certainly limitations. You don't want to stay on the C standard library stuff for very long - although things like malloc, printf, sscanf, etc. all do work. I've only just started looking into bank switching from within cc65 - it won't have any provisions for this "automatically" so the code space is limited to ~30K for the time being. You can manually switch banks and POKE (or "binary load") some code, and JSR over to it -- nothing prevents that. Just the cc65 linker won't do this "automagically" for you.
A "graceful exit" back to a working system is a hallmark of a professional and well developed application and polished development environment. I think the cx16.lib is close to being able to do that, it's not an inherent fault of cc65. And like the cx16, all the cc65 development is worldwide volunteers - as more interest in this target comes about, the right expert to resolve some of this may come about.