This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

Odd pointer assignment problem in CC65

Odd pointer assignment problem in CC65
by on (#157668)
I'm experimenting with writing C code for the NES, for future projects. Not sure if I'll stick with it or not, but I wanted to try anyway. I was able to figure out how to customize the C runtime that comes with CC65, and got as far as integrating my own startup code. And yes I know a few folks have provided libraries for all this stuff but I wanted to see if I could do it, for fun.

The following function works just fine (please assume I'm calling it during vblank):

Code:

#define PPUW (unsigned char*) 0x2007

void ppu_load_palette(const unsigned char* palette)
{
    int i;

    *PPUA = 0x3f;
    *PPUA = 0x00;

    for(i = 0; i < 32; i++)
        *PPUW = palette[i];
}


The result in FCEUX ppu viewer: Image

But at one point, I was (quite arbitrarily, just from having to get familiar with C again) assigning PPUW to a local variable, like this:

Code:
#define PPUW (unsigned char*) 0x2007

void ppu_load_palette(const unsigned char* palette)
{
    int i;
    unsigned char* ppuw = PPUW;

    while((*PPUS & 0x80) > 0);

    *PPUA = 0x3f;
    *PPUA = 0x00;

    for(i = 0; i < 32; i++)
        *ppuw = palette[i];
}


The result, in FCEUX ppu viewer:Image

Either I'm way rusty with C, or there's something else going on.

I was looking into using thefox's NintendulatorDX debugging stuff for this (to see what is actually being generated by the compiler...)---I thought I had seen that he could debug C using that---but the header files included seem to only be for CA65.
Re: Odd pointer assignment problem in CC65
by on (#157670)
CC65 generates astoundingly inefficient code when doing pointer math (on non-const pointers). You almost assuredly want to avoid pointers, except when it makes your code amazingly simpler.

CC65 always uses the (zp),y addressing mode for pointer math. (It doesn't really have a choice without doing tremendously more clever optimization).
The problem is that on a cycle-by-cycle basis, STA (zp),y takes 6 cycles:
* load instruction
* load zp
* load [zp]
* load [zp+1]
* load [[zp+Y]] ← without carry; also this is why you can't use this instruction on PPUDATA.
* write [[zp+Y]]
Re: Odd pointer assignment problem in CC65
by on (#157671)
From this response, and what I'm seeing in others' work---probably all interaction with the hardware should be done in assembly, not C, due to the unpredictable nature of the compiler? Probably should keep any C code I write to purely in-game logic, or updating buffers and the like?
Re: Odd pointer assignment problem in CC65
by on (#157679)
The part of your program that interacts with the hardware is called "drivers". On a 1.8 MHz machine on which compiled C runs slowly, you are right that drivers should be in assembly language.
Re: Odd pointer assignment problem in CC65
by on (#157683)
There was a thread about the addressing mode issue here a while back: http://forums.nesdev.com/viewtopic.php?f=2&t=9407

lidnariq already explained the problem, but basically it's not a good idea to write to hardware registers with C code. CC65 doesn't know how to treat these things the way they need to be.
Re: Odd pointer assignment problem in CC65
by on (#157696)
I agree that writing the hardware interfacing parts in assembly is the best option.

When I was doing KNES I actually didn't run into many problems with doing that stuff in C, but I guess that was because I was often making sure from the listing file (--listing) that the generated assembly was sensible. That said, in my experience I don't think you should expect to get many surprises if you write to a constant address from C. But given that cc65 doesn't even support volatile, writing to HW registers in C could potentially break in future versions. With any kind of indirection you also have the possible dummy reads/writes that could cause havoc.

BTW it's advisable to wrap the #define around one more set of parens, there are a couple of operators like [] in C that have higher precedence than the cast:
Code:
#define PPUW ((unsigned char*) 0x2007)

As for C support in NDX, I haven't tested it much. It might be currently broken.
Re: Odd pointer assignment problem in CC65
by on (#157704)
Thanks for the responses, all, much appreCiated.