Some cc65 compiler questions

Get technical support from the community & developers with specific X16 programs if you can't find the solution elsewhere
(for general non-support related chat about programs please comment directly under the program in the software library)
Johan Kårlin
Posts: 292
Joined: Wed Jun 03, 2020 11:33 am
Location: Kalmar, Sweden

Re: Some cc65 compiler questions

Post by Johan Kårlin »

Thanks for your helpful and long reply! Thanks for the attached file too. I really appreciate it. Hopefully it is helpful for others as well. Some comments and further questions:
voidstar wrote: Wed Nov 15, 2023 7:46 am You mentioned sourceforge? I haven't actively looked recently, but those prebuilds could be different than what is offered on github.
Actually, I found the link to sourceforge on GitHub in the README.md file. That is the only place to find executables, if I get it right. There are some releases on GitHub but they only contain source files.
voidstar wrote: Wed Nov 15, 2023 7:46 am 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.
Great tip! The stack is set to $800 in my config file. Still some valuable space to save. If my program exceeds the stack, how will I know? It will just crash and I have myself to blame, or?
voidstar wrote: Wed Nov 15, 2023 7:46 am 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.
voidstar wrote: Wed Nov 15, 2023 7:46 am 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.
This is what I am thinking about right now. Do you mean that you don't use any standard C functions at all? That is what you recommend? I could choose to do that quite easily, because I already have my own assembly routines for handling input, output, strings, files etc. But of course printf() is more handy with its support for formatted strings. On the other hand, I have noticed, it is too slow for me to use anyway. I suppose I also would free some valuable memory space if I skip the standard library.
Microdriver
Posts: 14
Joined: Tue Sep 19, 2023 9:58 pm

Re: Some cc65 compiler questions

Post by Microdriver »

voidstar wrote: Wed Nov 15, 2023 7:46 amSupport for float or double was never added.
Recently, I came across this project, which seems to apply float support of CC65 for the C64 target, by making use of the C64's kernal floating point routines:

https://github.com/mrdudz/cc65-floatlib

So right now, it's for C64, not Commander X16. I wondered, if it was possible to port this.
Also, how large can these C64 kernal routines be? A few K? Can't they just be provided by the library?
User avatar
desertfish
Posts: 1096
Joined: Tue Aug 25, 2020 8:27 pm
Location: Netherlands

Re: Some cc65 compiler questions

Post by desertfish »

The x16 kernal provides a largely compatible set of floating point routines, see https://github.com/X16Community/x16-doc ... th-library

So I think this particular library could be adapted to this.

Unfortunately you still won't get a real (no pun intended) floating point type in the language. (If you want that, consider using prog8 ahem ahem shameless plug)
voidstar
Posts: 494
Joined: Thu Apr 15, 2021 8:05 am

Re: Some cc65 compiler questions

Post by voidstar »

Correct, I avoid the "C standard library" stuff in cc65 except when "drafting" or "prototyping" an idea. DestinyHunter would not have been possible with their C standard library. And this isn't to say that library is "bad" - but it is "bloated" in that it will quickly bring in a lot of code that you probably don't need. printf and sscanf will quickly added 2-3K to the .PRG even if you only use very few of their features. cc65 has a "map" file output options that provides a concise summary of how many bytes each function consumes.


And yes, there is a concept of hooking directly into BASIC's already-implemented floating point mechanism. We were going to do that on the PET, but interestingly Steve Wozniak co-authored a paper on doing floating point on a 6502 (in '75 or '76, I think before even his Apple-1 work) which is also still a workable approach. I believe the KERNAL Math Library of the X16 uses the approach of hooking into the BASIC portions of the ROM - so it might not be the fastest, but it may use the least amount of memory (by using existing ROM calls and avoiding sets of tables here and there).



I'm not sure if I've actually "blown the stack" in any of my cc65 projects. I'm probably not ever more than 3 or 4 function calls deep (few address pointers on the stack -- which keep in mind the KERNAL stack is different than whatever cc65 reserved stack will be), and I got to where I don't even pass arguments to a function (it cost time to push/pop those onto the stack, just use a global variables -- which, yes, is horrible coding practice; at C64 1MHz we had to do foul things, but at 8MHz maybe more rigor on good-coding can be permitted; it really just how extreme you need to go to get the performance you need).

Blowing the stack probably has no real predictable result (maybe it depends on what is right after that stack space in the address). In the system memory map, "the system" (meaning the KERNAL itself) has a 256 byte stack for its own internal things - I doubt they spend runtime checking if you're at the end of that stack. There are situations where the X16 will "crash" and auto-jump itself into the system monitor -- I guess the prime example here is what we often see when we RUN and then RUN again on most typical cc65 built projects. I haven't looked too far how that works - for instance a system ISR maybe monitors the Program Counter to see if it has wandered into what is reserved as a data region; or the CPU may fire off "invalid opcode" interrupts somehow (which you can quickly run into when crashing into a data region). These are just guesses, I'll have to defer to a more X16 expert on it.


Some other examples:

#define GET_CX16_KEY(ch) \ __asm__("jsr $ffe4"); \ __asm__("sta %v", ch); typedef struct { unsigned char second_jiffies; // 4.25sec * 255 = 1083.75 seconds (about 18.0625 minutes) unsigned char first_jiffies; // 1/60sec * 255 = 4.25 seconds unsigned char jiffies; // each "tick" is 1/60th of a second } CX16_clock_type; CX16_clock_type cx16_clock; // use extern as needed void cx16_init_clock() { __asm__("LDA #0"); // jiffies __asm__("LDX #$FF"); // group1 __asm__("LDY #$FF"); // group2 __asm__("JSR $FFDB"); } void cx16_update_clock() { static unsigned char reg_a; static unsigned char reg_x; static unsigned char reg_y; __asm__("JSR $FFDE"); __asm__("STA %v", reg_a); __asm__("STX %v", reg_x); __asm__("STY %v", reg_y); cx16_clock.jiffies = reg_a; cx16_clock.first_jiffies = reg_x; cx16_clock.second_jiffies = reg_y; }

Here was my replacement for printf %d, if all I needed to output was a padded unsigned numeric value in decimal form (like a game score or health value):

#define WRITE_1U_DIGIT(x,y,val) \ WRITE_CHAR(x,y, 48 + val); // PU = pad unsigned void WRITE_PU_DIGIT(unsigned char x, unsigned char y, unsigned long val, unsigned char pad) { unsigned char index = 0; unsigned long multi = 10; while (TRUE) { if (val < multi) break; ++index; multi *= 10; } if (g_pad_char != '\0') { pad = pad-(index+1); while (pad > 0) { WRITE_CHAR(x, y, g_pad_char); ++x; --pad; } } while (index > 0) { --index; multi /= 10; WRITE_1U_DIGIT(x, y, val / multi); val %= multi; ++x; } WRITE_1U_DIGIT(x, y, val); }
Microdriver
Posts: 14
Joined: Tue Sep 19, 2023 9:58 pm

Re: Some cc65 compiler questions

Post by Microdriver »

So, if CC65 has its problems, what language would you suggest for the X16, if one wanted something faster than BASIC, but not as low level as assembly? Pascal? Prog8? C with another compiler?
User avatar
ahenry3068
Posts: 1135
Joined: Tue Apr 04, 2023 9:57 pm

Re: Some cc65 compiler questions

Post by ahenry3068 »

Prog8 and P65pas are both good options. There's a lot of cool work going on here in Prog8. It's very much a moving target as Desertfish is actively developing it, but he's also been very good with questions and technical support for the language. I currently finishing up a few BASIC projects and then I plan on giving P65Pas a spin, I've played a little with the compiler and it seems to make very efficient machine code. It's not as much of a moving target as Prog8 but there are far fewer people on here using it. I'm an old Turbo Pascal and fpc guy so that's why I'm going to give it a spin. BTW. You can do a LOT in BASIC on this platform and Stefan's BASLOAD make a little more modern approach feasible.
Johan Kårlin
Posts: 292
Joined: Wed Jun 03, 2020 11:33 am
Location: Kalmar, Sweden

Re: Some cc65 compiler questions

Post by Johan Kårlin »

voidstar wrote: Thu Nov 16, 2023 6:49 am And this isn't to say that library is "bad" - but it is "bloated" in that it will quickly bring in a lot of code that you probably don't need. printf and sscanf will quickly added 2-3K to the .PRG even if you only use very few of their features.
Yea, I have made som tests, implemented a highscore table in C, added ZSMKit and made some other stuff. The .PRG is now 13 Kb, so a third of low mem is already gone ... But I will limit the stack and implement my own "library".

Talking about stack overflow, i found this in the documentation for cc65 which seems practical when developing and testing:
7.4 #pragma check-stack ([push,] on|off)
Tells the compiler to insert calls to a stack checking subroutine to detect stack overflows.


Thanks for your code examples. Printing integers is exactly what I am after right now. Right now, I am adjusting the routines I have in my own assembly library to ca65 syntax. My plan is to mix C and assembly language in the future. I am tired of implementing user interfaces, menus etc, in assembly language, it is quite painful ...
voidstar
Posts: 494
Joined: Thu Apr 15, 2021 8:05 am

Re: Some cc65 compiler questions

Post by voidstar »

Nice find on that check-stack pragma, I hadn't come across that. Some other pragmas:

#pragma inline-stdfuncs (on) #pragma static-locals (on) #pragma register-vars (on)

Not sure if the inline-stdfuncs one works or actually helps, I ended up removing it for some reason.


BASLOAD is great, it really is "just BASIC without line numbers." So it's very low overhead in learning aspect about the system and experimenting with things. The CrazyLunar project was a pretty impressive example of what BASIC on this system can do. The two character variable limit is a drag, but Stefan seems close on being able to get a work around for get those up to 27 character limited.

Prog8 is super too - it'll have a bit of a learning curve, but any "development environment" is going to have that. cc65 has quirks, but obviously the C knowledge carries over to things like Arduino, etc. There was a vbcc project that could target 6502, but last I tried it a few months ago, it had a lot more limitations than cc65.

Here's a snippet for query mouse info:

unsigned int mouse_x = 0; // column (0-N) unsigned int mouse_y = 0; // row (0-N) char mouse_buttons = 0; void get_mouse_textmode() // "textmode" just cause the final x/y are divided by 8 { __asm__("ldx #$70"); // where in zeropage to store mouse x/y __asm__("jsr $FF6B"); // mouse_get __asm__("sta %v", mouse_buttons); // NOTE: Reg.X contains mouse wheel info (not currently used by XINFO) mouse_x = (((unsigned int)PEEK(0x0071) << 8) | (unsigned int)PEEK(0x0070)) >> 3; // >>3 for /8, textmode mouse_y = (((unsigned int)PEEK(0x0073) << 8) | (unsigned int)PEEK(0x0072)) >> 3; // >>3 for /8, textmode // NOTE: the above has a 16-bit intermediate (but doesn't really go beyond 640 or 10 bits) }
voidstar
Posts: 494
Joined: Thu Apr 15, 2021 8:05 am

Re: Some cc65 compiler questions

Post by voidstar »

Another "secret" about SYS call in BASIC is there are memory addresses used to send/receive the register values (around $030D). So that makes it easier to interact with .A .X .Y, when setting up for KERNAL calls, etc. I gotta get to the office, and will have to lookup the specific addresses later. (not really a secret, C64 had it, just it's not all that commonly remembered)

EDIT:
$030C: Accumulator .A $030D: X Register .X $030E: Y Register .Y $030F: Status Register/Flags
Last edited by voidstar on Fri Nov 17, 2023 6:02 am, edited 1 time in total.
User avatar
ahenry3068
Posts: 1135
Joined: Tue Apr 04, 2023 9:57 pm

Re: Some cc65 compiler questions

Post by ahenry3068 »

voidstar wrote: Thu Nov 16, 2023 2:49 pm Another "secret" about SYS call in BASIC is there are memory addresses used to send/receive the register values (around $030D). So that makes it easier to interact with .A .X .Y, when setting up for KERNAL calls, etc. I gotta get to the office, and will have to lookup the specific addresses later. (not really a secret, C64 had it, just it's not all that commonly remembered)
Just to add to that, a lot of the ROM routines also take parameters in the Zero Page. But BASIC can do that too.

Just
POKE (2-255), Value
(Don't ever Poke 0 or 1 directly, Use BANK instead.)
Post Reply