Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

cc65 competition?

73 views
Skip to first unread message

Harry Potter

unread,
Apr 12, 2008, 7:08:46 PM4/12/08
to
I want to create some software for the C64/128, Plus/4, Apple 2, NES
and maybe the Vic-20, Apple 2gs and SNES, under Win32 and an running
into problems. I tried cc65, but it isn't exactly feature-rich. I
tried Aztec C, and the programs in the SAMPLES directory (for the C64,
anyway) are *large* (>11k). I have Quetzalcoatl, and it could
probably produce small C64/Vic20 programs, but I haven't really tried
it. I want to create a cross-platform C compiler with the following
features:

* (Main feature) Support for hidden memory (i.e. $A000-$FEFF on a
C64) and banked memory (C128/Apple 2 128k memory)
* Support for longs and computer-specific float formats (both
disablable, saving code)
* Better optimizations
* Better __fastcall and register declarations
* Full zeropage support (direct pointer access and C variables in
ZP)
* Large programs separated into modules, each with its own main()
function, called through a stub
* The ability to replace a library module with another on the linker
command line
* Linker list files, rather than just on the command line

and whatever else I can think of. This program is giving me a hard
time with debugging, as it's so complex. Later, when I get the main
tools working sufficiently, I'll ask for help. Is this a good idea,
or did somebody already beat me to itr?

Bill Buckels

unread,
Apr 12, 2008, 7:55:38 PM4/12/08
to

Beat you to what? Some of what you are talking about are library
routines I think. The AUX memory stuff on the Apple II I already do...
and CC65 is doing something there too... what do you want to do
there???

How about the C64??? Harry what are you doing with overlays? OK and
did you look at the memory map that I am using with Aztec C?

I am creating holes where I want them and all that... I hardly think
the program code itself is large. Perhaps my load address, base
address, and what I am reserving for data is what you are reacting to.
How do you like what I am doing with the graphics compression and
such?

Quetezecoatl we all have too... it's not really C.

I think you need to step back and have a good look at the Aztec-C
compilers and then let's talk about how to get the source for them
released into the public domain and then make them ANSI compliant.

Of course that's my point of view so naturally I would say that:) And
I plan to do that too. If I can.

Glad you're having fun. You seem to have alot on your wish list...

Later,

Bill

Harry Potter

unread,
Apr 12, 2008, 8:26:22 PM4/12/08
to

How about internal calls to special direct AUX memory functions (read,
write, memory, string) and functions to execute functions in AUX
memory?

> How about the C64??? Harry what are you doing with overlays? OK and
> did you look at the memory map that I am using with Aztec C?
>

Er, what *is* the C64 memory map used by Aztec C C64?

> I am creating holes where I want them and all that... I hardly think
> the program code itself is large. Perhaps my load address, base
> address, and what I am reserving for data is what you are reacting to.
> How do you like what I am doing with the graphics compression and
> such?
>

Do you include *every* function in a library, or just the necessary
ones? cc65 seems to include justb the necessary ones, although some
fat (i.e. the initmainargs assembler function, which processes the
command line, shortened to pushing two NULLs on the stack) could still
be cut.

I want to compile a simple Hello, World!" program with just one
printf() function and see how it works.

> Quetezecoatl we all have too... it's not really C.
>

It could do for the Vic-20.

> I think you need to step back and have a good look at the Aztec-C
> compilers and then let's talk about how to get the source for them
> released into the public domain and then make them ANSI compliant.

I'm going to. Thank you.

Harry Potter

unread,
Apr 12, 2008, 8:52:34 PM4/12/08
to
On Apr 12, 8:26 pm, Harry Potter <maspethro...@aol.com> wrote:
> I want to compile a simple Hello, World!" program with just one
> printf() function and see how it works.
>

I just did that. The following is the listing of the main() function:

main()
{
printf ("HELLO, WORLD!\n");
getchar();

exit(0);
}

This code produced a 10.9k executable. If I only include the *used*
library functions, as cc65 does, I could easily cut down the code
size.

Bill Buckels

unread,
Apr 12, 2008, 10:49:13 PM4/12/08
to

I'll call the former owner of Manx and ask to have the code released
to PD if I can.

Then it can be optimized and twaeked. Give me a day or so.

Bill

Marc 'BlackJack' Rintsch

unread,
Apr 13, 2008, 5:52:55 AM4/13/08
to

It would be unnecessary big with `printf()`, at least with cc65, because
all the formatting code will be included. Try `puts()` for constant
strings instead.

And I don't consider 11 KiB that big. Remember that cc65 doesn't use the
BASIC ROM, so there is some "base part" that makes short programs seem to
look quite large compared to BASIC counter parts. Because the BASIC ROM
isn't needed you have about 50 KiB free RAM for C programs on the C64. So
part of your first feature, use of RAM from $a000-$cfff is already
implemented in cc65.

The RAM from $d000-$ffff is used by the graphics libraries that come with
cc65 or can be accessed through the "memory driver" API.

Ciao,
Marc 'BlackJack' Rintsch

Harry Potter

unread,
Apr 13, 2008, 6:56:57 AM4/13/08
to
On Apr 13, 5:52 am, Marc 'BlackJack' Rintsch <bj_...@gmx.net> wrote:
> It would be unnecessary big with `printf()`, at least with cc65, because
> all the formatting code will be included.  Try `puts()` for constant
> strings instead.
>

True, but if I exclude long and float support, I could probably
decrease overhead by as much as .5k.

> And I don't consider 11 KiB that big.  Remember that cc65 doesn't use the
> BASIC ROM, so there is some "base part" that makes short programs seem to
> look quite large compared to BASIC counter parts.  Because the BASIC ROM
> isn't needed you have about 50 KiB free RAM for C programs on the C64.  So
> part of your first feature, use of RAM from $a000-$cfff is already
> implemented in cc65.
>

11k is manageable, but what if I'm creating a program for the Vic20,
or for the C64 at $8000 or $C000?

> The RAM from $d000-$ffff is used by the graphics libraries that come with
> cc65 or can be accessed through the "memory driver" API.
>

True, but I'd like to access this data directly (i.e. declare it as
"hidden" and have the compiler automatically access this data through
a function cal whenever it is encountered). Functions wouldn't work
well on a C64, but they would in Bank 1 on a C128.

Oliver Schmidt

unread,
Apr 13, 2008, 2:15:15 PM4/13/08
to
Hi,

>cc65 seems to include justb the necessary ones

Of course. That's what a linker is for ;-)

>although some
>fat (i.e. the initmainargs assembler function, which processes the
>command line, shortened to pushing two NULLs on the stack) could still
>be cut.

1. The compiler contains a special optimization that doesn't pull in
initmainargs at all if main is declared as main(void). Check out your
map file to see what you actually get !

2. The initmainargs code lives in a special INIT segment which gets
overwritten later by the heap. So the memory in questions can be
reused.

Best, Oliver

BruceMcF

unread,
Apr 13, 2008, 3:00:34 PM4/13/08
to
On Apr 13, 6:56 am, Harry Potter <maspethro...@aol.com> wrote:
> 11k is manageable, but what if I'm creating a program for the Vic20,
> or for the C64 at $8000 or $C000?

If you are creating a program for the C64 at $C000-$CFFF, then
assemble it.

Rather than try to replace cc65, improve it. Then each feature on your
list is added to what cc65 already provides.

For example, an external function call interface for lc_65816, so
libraries can be written with cc65 code for the stock C64 and SuperCPU
code if the SuperCPU is available.

Also, it would make sense to use "register" declarations for local
variables that could benefit substantially from being in ZP locations,
since the idea of a register declaration seems to be widely understood
in the C world.

Harry Potter

unread,
Apr 13, 2008, 3:44:40 PM4/13/08
to
On Apr 13, 3:00 pm, BruceMcF <agil...@netscape.net> wrote:
> Rather than try to replace cc65, improve it. Then each feature on your
> list is added to what cc65 already provides.
>

I understand. Thank you.

Bill Buckels

unread,
Apr 13, 2008, 4:22:01 PM4/13/08
to
On Apr 12, 7:26 pm, Harry Potter <maspethro...@aol.com> wrote:
> > How about the C64??? Harry what are you doing with overlays? OK and
> > did you look at the memory map that I am using with Aztec C?
>
> Er, what *is* the C64 memory map used by Aztec C C64?

Generally I create a an explicit hole with the linker and push the
code and data past the graphics screen area, embed the graphics screen
directly into that area, embed a bitmapped font and graphics cursors
below that area etc.

I also do the same on the Apple II.

I use and provide (FREE) programs for both the Apple IIe and C64 Aztec
C Cross-Compilers that embed title screens into memory holes and load
fonts into these holes etc.

Read the following articles:

Adding Graphics and Fonts to a Compiled C64 Program

http://landover.no-ip.com/forums/index.php?topic=2241.0

Adding Title Screen and Graphics Cursors to a Compiled Apple IIe
ProDOS 8 Program

http://landover.no-ip.com/forums/index.php?topic=2241.msg8981#msg8981

>
> > I am creating holes where I want them and all that... I hardly think
> > the program code itself is large. Perhaps my load address, base
> > address, and what I am reserving for data is what you are reacting to.
> > How do you like what I am doing with the graphics compression and
> > such?
>

You had better read this one too... or the entire thread.

KOALA Paint and Other Bitmapped Graphics in Aztec C64

http://landover.no-ip.com/forums/index.php?topic=2243.0

> Do you include *every* function in a library, or just the necessary
> ones? cc65 seems to include justb the necessary ones, although some
> fat (i.e. the initmainargs assembler function, which processes the
> command line, shortened to pushing two NULLs on the stack) could still
> be cut.
>

The linker for any C compiler that I have ever used and there have
been many, explicitly links. You and I do not make that choice. Every
function is not included. That would be like DLL hell that these
Windows Mousemasters (myself included) have inflicted on us all in the
name of GUI interfaces.

All that a library is, is a bunch of object modules that are linked in
one at a time. You mentioned in some other email that you wanted to
use a list of object modules. Put those in a library. The command line
used to be much shorter but even now we use link libraries.

If you need a refresher on libraries and Aztec C go here:

LIBRARY MANAGEMENT and Libutil in Aztec C

http://landover.no-ip.com/forums/index.php?topic=2242.msg8982.0

> I want to compile a simple Hello, World!" program with just one
> printf() function and see how it works.

The guys that created these compilers were very smart men with lots of
compiler design knowledge and understanding. They knew how a linker
works obviously since they wrote the darned thing. They knew how an
optimizer works. Etc. THEY set the standards that you and I follow
today.

Try this link Too. Compiler Design by Alan Holub etc.

http://lua-users.org/wiki/CompilerWritingReferences

I had a look at what BlackJack was saying about program size. All C
compilers need start-up code and stack handling code and so forth...

Now with Aztec C you have the option of tweaking any of this and
redoing the libraries. Most of us don't think we're so darned clever
that we could of course and prefer to tweak our own code.

The beauty of the assembly pass is that you can optimize anything you
wish.

But choosing to use printf as the basis for a small functional program
is not what I would call a good test either (like BJ said already)...

I would need to rummage around alot in the compiler and tear apart
some libraries and so forth to trim this down to a special purpose
thing and I am not in the mood to do that right at the moment. What I
am in the mood to do is to try to get permission for the public domain
release of Aztec-C.

This may backfire on me and I may be told to take down my website, but
I am as ready as I'll ever be.

Have Fun Now!

Bill

BruceMcF

unread,
Apr 13, 2008, 7:18:56 PM4/13/08
to
On Apr 12, 8:26 pm, Harry Potter <maspethro...@aol.com> wrote:
> Do you include *every* function in a library, or just the necessary
> ones? cc65 seems to include justb the necessary ones, although some
> fat (i.e. the initmainargs assembler function, which processes the
> command line, shortened to pushing two NULLs on the stack) could still
> be cut.

No, just the ones you reference, directly or indirectly.

The killer with the modern desktops was calling a function, which
itself calls five functions, which themselves call twenty functions,
yadda yadda yadda, and the program is massive. That was fixed with
dynamic linking libraries, which can share the same library code. But
then one dynamic link library (.dll or .so) calls another one, and you
are off to the races again.

One of the ongoing developments in support of floppy disk and other
Tiny Linuxen is developing C libraries that are more fine grained in
terms of what is dragged in with the functions that you use.

The main thing for your situation is, if you call a function that can
also cook dinner and wash dishes afterward, like printf, then *even if
you don't ask it to do that*, the capability comes along for the ride.
So as a rule of thumb, use the function call that does the least in
addition to what you need, and it is likely to pull less additional
stuff in with it.

Harry Potter

unread,
Apr 18, 2008, 6:47:02 PM4/18/08
to

Let me add to that. I have some ideas that I think would improve
compiled C code:

* Calculation optimizations: All work would be done at compile
time, and only actual data modifications would be written to code.
* Stack optimizations: Instead of using the stack to save
intermediate results, I could use, on the inner-most ones, a zeropage
environment variable.
* Pointer/index: If possible, zeropage pointers would be referenced
directly or through an index.
* __fastcall and register declarations: I don't know if other 6502
C compilers do this, but I plan to allocate three words in zp for
register and __fastcall declarations and use unused environment space
for excess register declarations.

What do you think?

BruceMcF

unread,
Apr 18, 2008, 11:24:09 PM4/18/08
to
On Apr 18, 6:47 pm, Harry Potter <maspethro...@aol.com> wrote:
> On Apr 13, 3:44 pm, Harry Potter <maspethro...@aol.com> wrote:
>
> > On Apr 13, 3:00 pm, BruceMcF <agil...@netscape.net> wrote:
>
> > > Rather than try to replace cc65, improve it. Then each feature on your
> > > list is added to what cc65 already provides.
>
> > I understand. Thank you.
>
> Let me add to that. I have some ideas that I think would improve
> compiled C code:
>
> * Calculation optimizations: All work would be done at compile
> time, and only actual data modifications would be written to code.

Yes, that would be a normal optimization ... the first optimizations
are the easiest, and then the more aggressively you pursue it, the
smaller the returns, but given that the target is going to fit into a
64 address space it should be possible to be fairly aggressive.

> * Stack optimizations: Instead of using the stack to save
> intermediate results, I could use, on the inner-most ones, a zeropage
> environment variable.

OTOH, if the programmer has the best idea which inner routines are
going to be called the most often, a register local variable
allocation might be higher priority. Its a matter of balancing the zp
used by the compiler and the zp locations left free to assembly
language routines of the user ... given, of course, large chunks are
in use by the Kernal.

> * Pointer/index: If possible, zeropage pointers would be referenced
> directly or through an index.

With the 65816, this is easier, because it has the richer set of stack
indexed addressing ... with a 6502 C, often the stack pointer is
copied to the X index through TSX and the X-indexed address mode is
used for local variables ... $101,X; $102,X and so on ... which means
that zero page pointers through an index may involve register
juggling.

OTOH, a small register set means that its probably a bounded problem
with an unambiguous solution, and you use whichever way is the
best ... but there may have to be a speed/size priority setting.

> * __fastcall and register declarations: I don't know if other 6502
> C compilers do this, but I plan to allocate three words in zp for
> register and __fastcall declarations and use unused environment space
> for excess register declarations.

This seems like the biggest bang for the buck ... straightforward to
manage and much easier to manage, including direct use as pointers
rather than copying from the stack to a work location in the zero page
for indirect addressing.

Where is the environment in cc65?

> What do you think?

I think its going more deeply into C compiler programming than I'm a
mind to go, but especially the last one looks compelling.

Michael J. Mahon

unread,
Apr 19, 2008, 2:32:24 AM4/19/08
to
BruceMcF wrote:
> On Apr 18, 6:47 pm, Harry Potter <maspethro...@aol.com> wrote:
>
>>On Apr 13, 3:44 pm, Harry Potter <maspethro...@aol.com> wrote:
>>
>>
>>>On Apr 13, 3:00 pm, BruceMcF <agil...@netscape.net> wrote:
>>
>>>>Rather than try to replace cc65, improve it. Then each feature on your
>>>>list is added to what cc65 already provides.
>>
>>>I understand. Thank you.
>>
>>Let me add to that. I have some ideas that I think would improve
>>compiled C code:
>>
>>* Calculation optimizations: All work would be done at compile
>>time, and only actual data modifications would be written to code.
>
>
> Yes, that would be a normal optimization ... the first optimizations
> are the easiest, and then the more aggressively you pursue it, the
> smaller the returns, but given that the target is going to fit into a
> 64 address space it should be possible to be fairly aggressive.

Certainly doing constant computations at compile time is a good
start--and it permits the use of well-named constants in expressions
without compromising run-time efficiency.

>>* Stack optimizations: Instead of using the stack to save
>>intermediate results, I could use, on the inner-most ones, a zeropage
>>environment variable.
>
>
> OTOH, if the programmer has the best idea which inner routines are
> going to be called the most often, a register local variable
> allocation might be higher priority. Its a matter of balancing the zp
> used by the compiler and the zp locations left free to assembly
> language routines of the user ... given, of course, large chunks are
> in use by the Kernal.

For a 6502, zero page *is* the "registers". Nothing of interest to
a compiler--like pointers or integers--will fit in the processor's
registers.

>>* Pointer/index: If possible, zeropage pointers would be referenced
>>directly or through an index.
>
>
> With the 65816, this is easier, because it has the richer set of stack
> indexed addressing ... with a 6502 C, often the stack pointer is
> copied to the X index through TSX and the X-indexed address mode is
> used for local variables ... $101,X; $102,X and so on ... which means
> that zero page pointers through an index may involve register
> juggling.

Using a 256-byte stack for both return addresses and parameters is
really pushing it. ;-) The parameter & local variable stack should
almost certainly be a memory structure pointed to by a zero-page
pointer. Having it grow "against" the heap is pretty standard.

> OTOH, a small register set means that its probably a bounded problem
> with an unambiguous solution, and you use whichever way is the
> best ... but there may have to be a speed/size priority setting.

Zero page has room for several "general registers" that could hold
interesting data types.

>>* __fastcall and register declarations: I don't know if other 6502
>>C compilers do this, but I plan to allocate three words in zp for
>>register and __fastcall declarations and use unused environment space
>>for excess register declarations.
>
>
> This seems like the biggest bang for the buck ... straightforward to
> manage and much easier to manage, including direct use as pointers
> rather than copying from the stack to a work location in the zero page
> for indirect addressing.

And an option for inlining small functions can also be a big winner,
and a very effective time-space tradeoff.

-michael

NadaPong: Network game demo for Apple II computers!
Home page: http://members.aol.com/MJMahon/

"The wastebasket is our most important design
tool--and it's seriously underused."

BruceMcF

unread,
Apr 19, 2008, 11:54:06 AM4/19/08
to
On Apr 19, 2:32 am, "Michael J. Mahon" <mjma...@aol.com> wrote:
> For a 6502, zero page *is* the "registers". Nothing of interest to
> a compiler--like pointers or integers--will fit in the processor's
> registers.

Yes, but at the same time, much of low level interfacing with the
Kernal
from C involves treating zero page locations as either a global
integer
variable or global pointer variable.

I took it that he was referring to that kind of use of the zero
page ...
the zero page *used as* memory that is quicker to get to and quicker
to use when dereferencing a pointer.

> Using a 256-byte stack for both return addresses and parameters is
> really pushing it.

Yeah, I can see a pointer to a software stack structure passed on
the hardware stack before making the 6502 call.

With that, you only use the TSX register one time, at the start of
a called function, to set up the local variable pointer in the zp,
and possibly at the end if that slot in the hardware stack is used,
for ANSI C returns, as the pointer to the return value, or for K&R
returns, for the return value itself. So X would be free during
the routine, but Y would be in heavy use.

The general point stands ... without the built in stack frame address
modes of the 65816, there's going to be one of the two index
registers
that is in use to reference local variables.

> And an option for inlining small functions can also be a big winner,
> and a very effective time-space tradeoff.

Yes, I overlooked this entirely, but but there are a lot of
optimizations available for a zp routine that are not available
outside the zp.

Michael J. Mahon

unread,
Apr 19, 2008, 2:45:12 PM4/19/08
to
BruceMcF wrote:
> On Apr 19, 2:32 am, "Michael J. Mahon" <mjma...@aol.com> wrote:
>
>>For a 6502, zero page *is* the "registers". Nothing of interest to
>>a compiler--like pointers or integers--will fit in the processor's
>>registers.
>
>
> Yes, but at the same time, much of low level interfacing with the
> Kernal
> from C involves treating zero page locations as either a global
> integer
> variable or global pointer variable.
>
> I took it that he was referring to that kind of use of the zero
> page ...
> the zero page *used as* memory that is quicker to get to and quicker
> to use when dereferencing a pointer.

And page 0 is the natural place for "register" variables, both
the declared ones and the ones needed by the compiler/runtime.

>>Using a 256-byte stack for both return addresses and parameters is
>>really pushing it.
>
>
> Yeah, I can see a pointer to a software stack structure passed on
> the hardware stack before making the 6502 call.

You don't even need to pass it, since it is a global page 0 variable.

> With that, you only use the TSX register one time, at the start of
> a called function, to set up the local variable pointer in the zp,
> and possibly at the end if that slot in the hardware stack is used,
> for ANSI C returns, as the pointer to the return value, or for K&R
> returns, for the return value itself. So X would be free during
> the routine, but Y would be in heavy use.

Every function call/entry/exit maintains the global procedure stack,
so it never needs to be passed, and is always implicitly in "sync" with
the hardware stack for return addresses.

> The general point stands ... without the built in stack frame address
> modes of the 65816, there's going to be one of the two index
> registers
> that is in use to reference local variables.

True--or indeed to reference *anthing* relative to a pointer.

>>And an option for inlining small functions can also be a big winner,
>>and a very effective time-space tradeoff.
>
>
> Yes, I overlooked this entirely, but but there are a lot of
> optimizations available for a zp routine that are not available
> outside the zp.

If you take a "threaded code" approach for operations on larger
data types, then putting a bit of that code on page 0 can do
wonders for speed--at the cost of precious real estate, of course.

BruceMcF

unread,
Apr 19, 2008, 11:39:30 PM4/19/08
to
On Apr 19, 2:45 pm, "Michael J. Mahon" <mjma...@aol.com> wrote:
> You don't even need to pass it, since it is a global page 0 variable.

So its just a local stack frame in parallel with the hardware return
stack. I never felt the urge to crack the hood on C, but I realize it
is a lot more demanding of stack real estate than Forth.

Michael J. Mahon

unread,
Apr 20, 2008, 3:53:40 AM4/20/08
to

Exactly. And the stack demand depends on programming style--lots
of parameter or local variables means lots of stack frame.

Since style is out of control of the compiler, you have to assume
that there will be lots of stuff on the stack.

0 new messages