Page 3 of 5

KickC Optimizing C-Compiler now supports Commander X16

Posted: Mon Jan 18, 2021 7:58 am
by TomXP411


38 minutes ago, kktos said:




Tom, I guess that's related to what Jesper told you already about the compiler no "seeing" the var in the asm.

Therefore, here, as it doesn't see any use of R0, it simply removes it.

You need to use volatile in the declaration so the complier won't optimize it



Yeah, I tried that... still no joy.  The error I get is "unknown addressing mode". The compiler doesn't understand that STA (R0),Y should be an indirect , Y indexed instruction with the address of R0. 

The compiler does generate code for STA R0, which generates STA $02, but not for STA ($02),Y

 

 


KickC Optimizing C-Compiler now supports Commander X16

Posted: Mon Jan 18, 2021 3:41 pm
by SlithyMatt

Sounds like R0 is not getting recognized as an 8-bit value or there's a bug in cc65. Did you try just STA ($02),y?

For zero page addresses, you may need to have separate identifiers for zero page address values and usable pointers.


KickC Optimizing C-Compiler now supports Commander X16

Posted: Mon Jan 18, 2021 7:43 pm
by Jesper Gravgaard


12 hours ago, TomXP411 said:




I am working on it now... part of the problem is I really don't understand your assembly/c interface very well, and your calling convention is not something I've seen before. 



For example, I wanted to fill a buffer in the data segment, with the pointer stored in RO (address 2 in zero page). I'd expect something like this to work...



in my global section:



  __address($02) word R0;



char* buffer ..... 



...



R0 = (word) buffer;



asm {



  STA (R0),Y



...



}



}



But the compiler just completely removed the assignment to R0, then failed to assemble the STA line because R0 didn't exist. 



I ended up using a really obtuse syntax with a double pointer that I pulled out of your LOAD example, but I don't understand why the code above doesn't work. 



 



I have tried to create a minimal example re-creating your problem - but it seems my programs cannot reproduce your problem.

The following is my C-program  


__address($02) word R0;

 


void main() {



  char* buffer = 0x0400;



  R0 = (word) buffer;



  asm {



    sta (R0),y



  }



}


And this is the resulting ASM of the main function, when compiling with version 0.8.5:


main: {



  .label buffer = $400



  lda #<buffer



  sta.z R0



  lda #>buffer



  sta.z R0+1



  sta (R0),y



  rts



}


I believe this is what you wanted to see.

Could you show a little more of your code (or share the entire file). Then I will look into the problem you are facing.

/Jesper


KickC Optimizing C-Compiler now supports Commander X16

Posted: Mon Jan 18, 2021 7:48 pm
by Greg King

Does the assembler understand capital letters for the register names?


KickC Optimizing C-Compiler now supports Commander X16

Posted: Tue Jan 19, 2021 1:02 am
by TomXP411


Quote




Does the assembler understand capital letters for the register names?



Thanks for the tip: that's exactly what it was. The compiler fails two different ways if you:


  1. Write the mnemonics in upper case. 


  2. Write register operands in upper case


Now that I know, I'll make sure to lower-case mnemonics and register operands. 

And now that I've done that, I can now read 256 bytes from a file directly into a memory buffer. I've actually got two more extensions to make to that method: stop on null, and stop on CR. 

On that note @Jesper Gravgaard, I'm considering the naming convention for the CMDR File I/O routines. 

I started using fopen, fgetc, and fgets, but the signature of all those does not match the conventions in the ANSI C stdio library.

for example, my fopen looks like this:

void fopen(byte channel, byte device, byte secondaryAddress, char *filename)

while ANSI's stdio looks like

FILE * fopen ( const char * filename, const char * mode );

Would it be better to rename the routines, or just overload the standard names with the platform-specific signatures? 

The names I'm considering are: cxopen, cxgetc, cxgets, cxseek, cxputc, cxputs, and cxclose. This keeps the original fopen() and related function names free, in case someone decides to implement a standardized version of those functions in the future. 

 

 

    


KickC Optimizing C-Compiler now supports Commander X16

Posted: Tue Jan 19, 2021 7:24 am
by Jesper Gravgaard

I am glad you got everything to compile! How ASM and C works together can still use some work - both improvements of the features allowing for for inlining ASM easily and the documentation of how you use it.


6 hours ago, TomXP411 said:




The names I'm considering are: cxopen, cxgetc, cxgets, cxseek, cxputc, cxputs, and cxclose. This keeps the original fopen() and related function names free, in case someone decides to implement a standardized version of those functions in the future. 



I believe that is a good starting point! 

If they are common enough to be easily portable to the other commodore platforms maybe they should be called cbmopen, cbmgetc, ...

 


KickC Optimizing C-Compiler now supports Commander X16

Posted: Tue Jan 19, 2021 8:19 am
by TomXP411


50 minutes ago, Jesper Gravgaard said:




I am glad you got everything to compile! How ASM and C works together can still use some work - both improvements of the features allowing for for inlining ASM easily and the documentation of how you use it.



I believe that is a good starting point! 



If they are common enough to be easily portable to the other commodore platforms maybe they should be called cbmopen, cbmgetc, ...



Thanks. I'm moving forward, slowly but surely. My next step is to implement the command channel, so I can issue disk commands. Once that's done, I can start working on the UI code.

 


KickC Optimizing C-Compiler now supports Commander X16

Posted: Tue Jan 19, 2021 11:35 pm
by TomXP411

Just another question, and I know this one comes out of left field...

I was talking about a windowing library on another thread, and I am wondering if there's a way in KickC to generate an object file that does NOT optimize away unused functions. I'm thinking about how to create a function library that I can burn into ROM and make available to other programs later. Right now, your compiler seems to simply ignore functions that aren't called from another function, and when they are called, there's a lot of coupling at the assembly level. 

For example, if I have a routine named print(char* text), the text variable isn't always passed as a distinct value; instead, the compiler simply grabs the original declaration in the calling function and references that directly in the callee. I don't see evidence of using the stack or heap to marshal parameters, like in the C calling convention. 

It seems easy enough to devise my own marshaling subsystem, by using __address variables to directly access the R0-R15 byte pairs in zero page (the first 32 bytes are set aside for parameter passing.)  But I don't see a simple way to force the compiler to include a non-referenced function. 

I guess what I'm asking is... is there a way to force a function to be compiled, even if it's not used, and is there a way to force the C calling convention of putting parameters on the stack or a stack-like structure?

 


KickC Optimizing C-Compiler now supports Commander X16

Posted: Wed Jan 20, 2021 5:13 pm
by Jesper Gravgaard


17 hours ago, TomXP411 said:




I was talking about a windowing library on another thread, and I am wondering if there's a way in KickC to generate an object file that does NOT optimize away unused functions. I'm thinking about how to create a function library that I can burn into ROM and make available to other programs later. Right now, your compiler seems to simply ignore functions that aren't called from another function, and when they are called, there's a lot of coupling at the assembly level. 



It seems easy enough to devise my own marshaling subsystem, by using __address variables to directly access the R0-R15 byte pairs in zero page (the first 32 bytes are set aside for parameter passing.)  But I don't see a simple way to force the compiler to include a non-referenced function. 



I guess what I'm asking is... is there a way to force a function to be compiled, even if it's not used, and is there a way to force the C calling convention of putting parameters on the stack or a stack-like structure?



 



There is no direct support (like a keyword) for this at the moment. However, it can be achieved, with a little linker trick.

By creating a linker specification that declares a segment that is not included in the generated binary file then we can use the main() function to call all the ROM functions - but ensure that the main function itself is not included in the binary.

I have created an example C-file and linker configuration file that creates a ROM at $F000 with three functions.

The example also shows how to pass parameters and return values in three different ways:

- through the stack

- through zeropage 

- through registers (and/or zeropage)

You can see the code here: https://gitlab.com/camelot/kickc/-/tree/master/src/test/kc/examples/rom

Let me know if this makes sense, or if it leads to new questions.


KickC Optimizing C-Compiler now supports Commander X16

Posted: Wed Jan 20, 2021 10:51 pm
by TomXP411


5 hours ago, Jesper Gravgaard said:




There is no direct support (like a keyword) for this at the moment. However, it can be achieved, with a little linker trick.



By creating a linker specification that declares a segment that is not included in the generated binary file then we can use the main() function to call all the ROM functions - but ensure that the main function itself is not included in the binary.



I have created an example C-file and linker configuration file that creates a ROM at $F000 with three functions.



The example also shows how to pass parameters and return values in three different ways:



- through the stack



- through zeropage 



- through registers (and/or zeropage)



You can see the code here: https://gitlab.com/camelot/kickc/-/tree/master/src/test/kc/examples/rom



Let me know if this makes sense, or if it leads to new questions.



That's perfect. I had come to a similar conclusion, but was unsure how to prevent main() from being included or executed. 

So, looking at the calls in main, where you call each function twice with two different parameters -  I suspect that's to fool the optimizer into using proper parameter passing, rather than converting the parameter into a shared variable?

 

Thanks!