CA65 + CC65

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
CA65 + CC65
by on (#16323)
So I took the plunge and decided to try and move away from NESASM due to its buggy behavior, switching to CC65 instead. The syntax isn't all that different, mostly labels and such. The thing that threw me for a loop for a few minutes was the notion of needing to use a seperate config file to setup the code segment and memory locations and such. There's a much appreciated simplicity with NESASM where I simply use .bank and .org to fill the gaps and such I need in a rom image.

In any case, I got the assembly aspect down for the most part, so I thought I'd look into including some C, in case I might ever want to whip up a function right quick for testing, and then do an assembler version later. Calling C functions from assembly seemed fairly straight forward and I had it working fairly quickly. The problem, however, involves the use of variables. The first time through, they simply don't work properly.

By first time through, I mean when I first execute the code in an emulator (FCE Ultra), it's messed up; any variable references are totally incorrect. But if I use the reset command, suddenly it works fine. It's as if it's setting up something during the first run, despite failing to work properly, which allows the second attempt work fine, since the reset command is apparently just a soft reset and doesn't reset memory (like a real NES from what I understand). Other emulators aren't as forgiving, and don't work with the rom at all.

For example:

unsigned char * const ppu_reg1 = (unsigned char*)0x2000;
...
*ppu_reg1 = 0x90;

Assigning a value to *ppu_reg1 does nothing the first time through. The second time, as mentioned above, it works correctly. Something to note is that if I don't use "const" on the pointer, it doesn't ever work, soft reset or not. However, if I use, for example:

*((char *)0x2000) = 0x90

It works every time, because obviously there's no variable references.

It's not just limited to accessing pointers, either. Something like..

unsigned char n = 0x90;
*((char *)0x2000) = n;

..ends up with the same results. $2000 gets set with a value, but it's not what it's supposed to be on the first pass.

One thing that came to mind is that maybe I'm supposed to initialize the C runtime library, but I'm at a loss for how to do so. The other thing is that my segment/memory file might be incorrect. But there's possibly so many reasons for it to not work, some of which I'm prolly not even thinking of, that I don't really know where to start.

I'd post code, but there's multiple files, so unless it's needed to diagnose such a problem, I'll leave it off for now. I figure somebody with more experience at CC65 might already know what I'm talking about.

The other small question is if anyone has a reference for the functions in nes.lib file. There seems to be many functions in there which aren't documented whatsoever in the stuff that comes in the cc65 documenation archive. Though that particular NES documentation seems to be lacking all around anyway.

Anyhoo, thanks in advance!
Re: CA65 + CC65
by on (#16329)
FyberOptic wrote:
The thing that threw me for a loop for a few minutes was the notion of needing to use a seperate config file to setup the code segment and memory locations and such.

It's the same on almost any other platform such as PC, Mac, GBA, and Nintendo DS, where the config file is called a "link script".

Quote:
By first time through, I mean when I first execute the code in an emulator (FCE Ultra), it's messed up; any variable references are totally incorrect. But if I use the reset command, suddenly it works fine.

Are you forgetting to initialize variables by copying the DATA segment into RAM and zeroing BSS in your init code?

Quote:
One thing that came to mind is that maybe I'm supposed to initialize the C runtime library, but I'm at a loss for how to do so.

LD65 manual section 5.4 should explain.

Quote:
I'd post code, but there's multiple files, so unless it's needed to diagnose such a problem, I'll leave it off for now. I figure somebody with more experience at CC65 might already know what I'm talking about.

Based on what I've seen, most nesdev.com forum members just use CA65 and LD65 and skip the C compiler. I never thought of trying the C compiler because unlike the rest of the CA65 package, the C compiler is not free software.

by on (#16356)
I've played around with the compiler, basically just wrote a hello world program in it. Unfortunately the NES library is busted. It worked on FCEUltra but not on my NES (or on Nintendulator, I think). I was screwing around with fixing it (I think I did fix something in it, I forget what), but I couldn't find where the major problem(s) exist.

Writing your own functions should work just fine though, I'd think. I never tried that (calling them from the assembly program). I find it really interesting. It seems we're the only ones trying to use the C compiler for NES at all (but you're obviously trying harder than me, heh).

You said you've got the assembler stuff down, but if you want to see the linker script (nes.cfg) that's like what I use I've had a copy uploaded here for a while: http://www.parodius.com/~memblers/nes/

tepples wrote:
I never thought of trying the C compiler because unlike the rest of the CA65 package, the C compiler is not free software.


What's not free about it? While it's slightly more restrictive than the rest of the package (which literally says you can do anything with it except misrepresent it's origins), it seems to be pretty much like the GPL. Just requiring source release for any modifications to the compiler.

by on (#16359)
Memblers wrote:
tepples wrote:
unlike the rest of the CA65 package, the C compiler is not free software.

What's not free about it?

One of the requirements in the CC65 license is
Quote:
1: You don't charge anything for the copy. It is permissable to charge a nominal fee for media, etc.

This imposes limitations on making and distributing copies for a fee. The GNU General Public License doesn't permit this limitation in general, and neither does any other license that meets the Debian Free Software Guidelines or the OSI's Open Source Definition. (The GPL section 3c may appear similar at first, but it applies only when source code and executables are distributed separately.) See also Selling Free Software.