Some cc65 compiler questions
-
- Posts: 292
- Joined: Wed Jun 03, 2020 11:33 am
- Location: Kalmar, Sweden
Some cc65 compiler questions
I have just started with cc65. There is a thorough documentation, fantastic. But here's some questions. Maybe you know the answer to one or some of them? I have v 2.19 for Windows 64-bit downloaded today, nov 13.
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?
2. The generated BASIC stub is "531 SYS 2061". Is something wrong or why "531"?
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.
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?
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.
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?
2. The generated BASIC stub is "531 SYS 2061". Is something wrong or why "531"?
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.
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?
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.
-
- Posts: 14
- Joined: Tue Sep 19, 2023 9:58 pm
Re: Some cc65 compiler questions
Yeah, noticed that too. Don't know how to avoid it yet. In this demo, he does:Johan Kårlin wrote: ↑Mon Nov 13, 2023 1:54 pm3. 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.
Code: Select all
// Switch back to the uppercase character set.
cbm_k_bsout(CH_FONT_UPPER);
No, you should be able to run it several times. Did you call "printf()" or "puts()"? Better show the exact code.Johan Kårlin wrote: ↑Mon Nov 13, 2023 1:54 pm4. 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?
-
- Posts: 292
- Joined: Wed Jun 03, 2020 11:33 am
- Location: Kalmar, Sweden
Re: Some cc65 compiler questions
Microdriver wrote: ↑Mon Nov 13, 2023 4:24 pm No, you should be able to run it several times. Did you call "printf()" or "puts()"? Better show the exact code.
Code: Select all
#include <stdio.h>
void main() {
printf("Hello world!");
}
-
- Posts: 14
- Joined: Tue Sep 19, 2023 9:58 pm
Re: Some cc65 compiler questions
I'm compiling on Linux and have that problem too. Also, when I return 0 from main().
Well, maybe when running the assembly code that was compiled from the C code, it changes something in the memory, so when the memory address is called again, it finds different bytes and does something unexpected. Just a guess.
Well, maybe when running the assembly code that was compiled from the C code, it changes something in the memory, so when the memory address is called again, it finds different bytes and does something unexpected. Just a guess.
-
- Posts: 292
- Joined: Wed Jun 03, 2020 11:33 am
- Location: Kalmar, Sweden
Re: Some cc65 compiler questions
Ok, at least it's not just me then. Yes the code seems to change something that cannot be left in another state.
When it comes to the mystic "531" row number, I have discovered something: If I get it right you can define the BASIC stub yourself. It is done in the demo for ZSMKit. First, a segment is defined in the configuration file, then the content of the segment is defined in the source code. https://github.com/mooinglemur/zsmkit/b ... src/main.s
When it comes to the mystic "531" row number, I have discovered something: If I get it right you can define the BASIC stub yourself. It is done in the demo for ZSMKit. First, a segment is defined in the configuration file, then the content of the segment is defined in the source code. https://github.com/mooinglemur/zsmkit/b ... src/main.s
Re: Some cc65 compiler questions
cc65 is notorious for not leaving the machine set up correctly to run BASIC; it trashes various system variables and vectors when doing its own runtime setup. You pretty much have to call for a full system reset on exiting your program.
Re: Some cc65 compiler questions
I have the same issue, every time I've used cc65 to make even simple test programs, it crashes to monitor if I try to run them a second time. The X16 doesn't have any standard way of actually terminating a program, and even the C64 usually required you to press the reset button to exit a program, so I just figured ASM programs "cleanly" terminating to BASIC was going to be an exception rather than a rule.
Getting a nightly build seems to be fine, I don't think the X16 portion of cc65 is changing very much unless it's one of us doing a pull request or something.
Getting a nightly build seems to be fine, I don't think the X16 portion of cc65 is changing very much unless it's one of us doing a pull request or something.
Re: Some cc65 compiler questions
I think that's just on the emulator, isn't it? It simulates the light on the disk drive. If you look closely you will see that it also lights up very briefly when you access a file successfully. If there is a file error of any kind, the light will blink. You have to reset the error state for it to disappear.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.
I haven't found out how myself, though... using READST etc. doesn't do anything. I assume using the command channel (15) could solve this.
-
- Posts: 292
- Joined: Wed Jun 03, 2020 11:33 am
- Location: Kalmar, Sweden
Re: Some cc65 compiler questions
Thanks for telling me. Then I can let this go. It is not a big deal, it is just that I am - quite unnecessary - attached to the idea of returning the machine in an uncorrupted state. I guess this marks the end of making games with a "quit game" option .
Good to hear. Hopefully, there will be no problems. The compiler has been around for such a long time, so I guess breaking changes are unlikely. But still, I would prefer official releases.
That must be it. It feels like I should have thought about that myself, but it was a long time since I used a disk drive. Great, I can check that off the list of things to sort out.AndyMt wrote: ↑Tue Nov 14, 2023 7:06 am I think that's just on the emulator, isn't it? It simulates the light on the disk drive. If you look closely you will see that it also lights up very briefly when you access a file successfully. If there is a file error of any kind, the light will blink. You have to reset the error state for it to disappear.
Re: Some cc65 compiler questions
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 ]
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.
#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.
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.
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.
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.}).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?
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.
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 2. The generated BASIC stub is "531 SYS 2061". Is something wrong or why "531"?
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: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.
#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.
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).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?
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.
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.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.
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.
- Attachments
-
- core_x16.h
- (10.07 KiB) Downloaded 437 times