
C++14 for the Commodore 64 [video] - ingve
https://www.youtube.com/watch?v=nLv_INgaLq8
======
white-flame
Static optimization to inlined code that ONLY handles immediate numbers and
addresses is fine, and interesting to see the full pipeline working. But that
possibility is there really for any language and any asm platform. I remember
seeing Forth compile down to 6502 or other asm code, where it compiled down to
the asm instructions a human would write for the same task, with basically
zero language overhead.

HOWEVER, that was because the code written only did things similar to assembly
instructions, similar to this example.

The biggest problem with compiling C family languages to 6502 is the stack.
They generally assume something like a local stack frame for variables and
parameters, and there's no way to directly express that style of programming
at the 6502 instruction level. Note that there were no local variables in
these examples, much less any actual function calls. Certainly the ABI used by
C would not be machine-code-translatable from x86 to 6502; there would be an
ABI written for 6502 and higher level targeting could work.

Instead of generating & trying to translate x86 assembly code, compiling C++14
down to plain C and using a 6502 compiler like cc65 could work significantly
better for more idiomatic C++.

While it's an interesting novelty, why write 50+ lines of C++ code when
writing 7 lines of commented, well-understood assembly instructions suffice?
Add some variables and macros to take care of naming the various bits &
locations, or target some codegen directly to 6502 if we're talking about
programming "in the large" relatively speaking. Sure, you don't want to touch
x64 code for human writing in the general case, but 6502 was designed with
hand coding in mind.

~~~
to3m
Yes. This doesn't strike me as an especially productive line of attack, but
maybe I'm missing something (hopefully not obvious), maybe I'm just not
imaginative enough, and/or maybe I'm underestimating how much effort people
might be willing to put into such an endeavour.

This did get me thinking about the problem a bit this evening though. The 6502
is an awful target for many higher-level languages, but I think you could
compile something like C, if you treat zero page as the stack for locals, and
index it by X. The programmer would need to be aware of the target's rather
tiresome limitations, but you'd get somewhat passable code at least.

(Unlike absolute addressing, you do pay a 1-cycle penalty for indexed zero
page accesses, but what can you do? You need to store things in zero page to
handle pointers.)

Suppose you had a function with a couple of locals, like this:

    
    
        void strip(char *p,char c) {
            unsigned char *dest=p;
            do {
                if(*p!=c) *dest++=*p;
            } while(*p++!=0);
        }
    

So you'd store c (1 byte), then p (2 bytes), and then once the space for
locals is reserved, zero page starting from the address in X would look like
this:

    
    
        +0, +1 = dest
        +2, +3 = p
        +4     = c
    

So the ideal generated code would go along these lines:

    
    
        DEX:DEX                         ; reserve space for locals
        LDA 2,X:STA 0,X:LDA 3,X:STA 1,X ; dest=p
        .L0
        LDA (2,X)                       ; *p
        CMP 4,X
        BEQ L1                          ; taken when *p==c
        STA (0,X)                       ; *dest=*p
        INC 0,X:BNE L2:INC 1,X:.L2      ; ++dest
        .L1
        LDA (2,X)                       ; *p
        INC 2,X:BNE L3:INC 3,X:.L3      ; ++p
        CMP #0
        BNE L0                          ; taken when *p!=0
        INX:INX
        RTS
    

I don't think many people would write code like that by hand, but it's not
completely insane given the requirements.

This has actually now piqued my interest enough to make me think about
actually coding something, so I guess that answers the question about how much
effort somebody might be willing to put into such an endeavour.

Other thoughts:

\- since ZP,X costs like ABS,Y, maybe have a second stack in main memory for
non-pointers and index it with the Y register (the RMW instructions don't have
an appropriate addressing mode though)

\- you could statically allocate zero page for many programs, which would make
it easier to use the (ZP),Y addressing mode

\- turning canned snippets (like the INC/BNE/INC) into routines would probably
be rarely beneficial, since getting the address into X is rather involved

\- I've never used a C compiler for the 6502 so maybe they all do this anyway
;)

~~~
white-flame
cc65 ([http://cc65.github.io/cc65/](http://cc65.github.io/cc65/)) is probably
the most popular C compiler for the 6502, and its has support for many of the
old home computers. I only use its assembler, since it's one of the most
powerful, but I'm somewhat familiar with its C side of things.

I believe it uses a manual 16-bit stack pointer for frames, and zeropage for
globals and statics. Pointers have to be copied into zeropage to be
dereferenced, and I think it might have a numeric stack somewhere for
intermediate results when evaluating numeric expressions. It's not super fast
by any measure (simply due to impedance mismatch between C and 6502), but it
does work and is quite mature.

As a side note, most 6502 Forths do use zeropage for the operand stack, with
heavy use of zp,X addressing in their operators.

------
richard_todd
My eyes couldn't look away from the extra "= 0x01" at the top; it was driving
me nuts. Glad he noticed it before the end of the video.

The middle part got me thinking: how helpful is it really, to write 50+ lines
of high-level code, just to get 8 assembly instructions? I get that it's more
readable and whatever, but seriously, I might rather write the 8 assembly
lines and be done with it. Maybe I've spent too much time on comp.lang.forth
lately :)

~~~
unsignedqword
Well, you said it yourself: it's more readable; not to mention more easily
maintainable and extensible. If we all sought to create the most terse code
possible with no regard to any of the other important factors in creating
'good code', then we all might as well be writing everything in Pyth or APL.

EDIT: I wouldn't say that all assembly is unreadable or anything like that
(for instance, I find inline assembly easier and more readable than using
compiler intrinsics for stuff like AMD64 SIMD instructions). I'm just saying
that having more code around isn't exactly always a bad thing.

------
TillE
Really watchable video. Nothing fancy, just pleasantly concise.

The transparent optimization of modern (and not-so-modern) C++ features is not
surprising, but it's cool to see in action.

------
egypturnash
Why is he doing this with an x86 compiler. The c64 used a 6510. None of this
code would ever work.

...Oh, if you jump to about halfway through he starts using an x86->65xx
translator. Okay. Nice.

~~~
Hydraulix989
There already seems to be a 6502 backend for LLVM specifically geared for c64:

[https://github.com/c64scene-ar/llvm-6502](https://github.com/c64scene-
ar/llvm-6502)

Which means you can just use the clang frontend and even write C++17 code
which compiles down to 6502 ML.

~~~
lefticus
I was unable to get any of the existing 3 llvm 6502 backends to produce
reasonable code. Which is why I went this route. I meant to mention that in
the video...

~~~
hermanhermitage
There's also
[https://github.com/puppeh/gcc-6502](https://github.com/puppeh/gcc-6502) and
[https://github.com/puppeh/gcc-6502-bits](https://github.com/puppeh/gcc-6502-bits)
to get 6502 directly out of gcc.

~~~
lefticus
I don't believe I found those, thank you.

------
vitd
Oh man, I remember trying to understand AppleDOS and 6502 Assembly on the
Apple II+ when I was a wee lad. It was so confusing what all these hex memory
locations were. Being able to give them actual function names (or even just
named constants!) would have made things so much easier!

------
jandrese
Nothing gives the warm fuzzies like seeing the translator step couldn't parse
anything except the code he specifically wrote for the demo...

~~~
lefticus
Functional calls are not handled, which is part of the problem. There are
several working examples in the x86-to-6502 repository. Please add more
examples and help with additional translation.

------
ktRolster
The _spec_ for C++14 wouldn't fit on a Commodore 64. At 1300 pages, it
wouldn't even fit on external storage (170k floppies).

~~~
plexchat
Yes because the code emitted by a compiler is directly proportional to the
size of the specification? I fail to see the point.

~~~
ktRolster

      >I fail to see the point.
    

That's ok, you don't need to see everything.

~~~
banachtarski
Humor me then. What's the point?

------
Feneric
Really cool, and this same approach looks like it'd work out-of-the-box with
the C128 as a target, too.

------
arunc
Pleasant and interesting. Has anyone tried similar stuff with D?

~~~
lefticus
This was another reason I went the x86->6502 route instead of just a 6502
backend for llvm - it could plausibly work with any code. Let me know what you
find.

