1. 19

This post is in the middle of a forum thread about the developer’s NES game. Compares cc65, KickC, 6502-gcc, vbcc and handwritten 6502 assembly for some common in-game usages.


  2. 4

    More suitable to the 6502 architecture than C, more modern than FORTH: https://github.com/dschmenk/PLASMA. It would be interesting to add it to the comparison.

    1. 1

      I also became aware of Cowgol very recently, and I wish I had some time to devote to playing with it. It’s intended to be small enough to one day be self-hostable on those tiny machines.

      Plus, I don’t think any other language gives a shoutout to the Apollo guidance computer on its front page:

      (It used to support the Apollo Guidance Computer used in the Apollo spacecraft, but I had to remove the code generator while rewriting the compiler and I haven’t reworked the AGC backend.)

    2. 3

      This is a great post, would love to see one where they dig into the assembly listings.

      In C, when you declare a function without preceding it by “static”, it has to be accessible to other compilation units, it must be there and fully usable: passing parameters on stack and all that.

      FWIW, Link Time Optimization (-flto) can greatly help with this by allowing inlining across compilation units.

      I expect 6502-gcc doesn’t have architecture support for LTO yet, but maybe some GCC wizard will implement it…

      1. 3

        I’m surprised anyone bothers with C on the 6502. A 256 byte stack, three 8-bit registers (only one of which can be used for math) and very poor index addressing modes makes for a very poor C experience. And as far as LTO goes, you only have a total of 64K RAM. In most cases, you don’t want to inline code.

        1. 5

          FORTH seems a better choice than C on the 6502, since it’s so damn compact. I used to use FigFORTH on my Apple ][ back in high school once I outgrew BASIC.

          1. 4

            C on low-level platforms also makes sense as a kind of glue language. So what you’ll commonly find is that large portions of a game or demo are in fact written in asm, with a bit of C sprinkled on top for tying the various bits and pieces together. Just saves a lot of work for those boring but necessary things where performance doesn’t really matter. cc65 is especially useful in this respect, since comes with a very good assembler.

            Anyway, great find, thanks for posting!

            1. 1

              I actually like being able to type an int as a 16bit entity and then just have the compiler fix the additions and subtractions for me (sprite X positions spring to mind), even if the code ends up exactly as a simple Add16() macro in asm would end up, I just don’t have to macro it every time. If inlining or linking pure asm is easy then you can well use C for the non-critical stuff, and asm for your interrupts and so on.

            2. 2

              A lot, if not most? of the code still being written for the 6502 today is in the form of retrogames, which are a… surprisingly active market for software that’s written for fossil hardware :). That makes code reuse worthwhile and many developers and game studios tend to shy away from writing everything in ASM and Forth. There are a bunch of reasonably good libraries (see e.g. neslib), written in pretty well-optimized assembly. In lots of games, C is to these libraries as Lua is to a modern game engine, more or less. Plus ROM space is pretty cheap. You can go a long way writing the boilerplate in C, and the tight loops in ASM.

              (Sauce: running wc on my current NES project says about 21K lines and I’m about 2/3rds of the way through :P. It would’ve probably been way better if I’d done it in ASM but it would’ve taken a lot longer, especially since it’s, you know, a game, where lots of things have been written two or even three times until they were juuuust right. You can’t quite waterfall your way through this.)

              1. 2

                That’s fair. I was also a bit amazed to see that there are not one but multiple C compilers available for 6502! Which is why I’d like to see the assembly listings and see what kind of different “tricks” these compilers are doing (possibly none I guess, but the benchmarks suggest some big differences in their code generation approach and/or possible optimisations).

                as far as LTO goes, you only have a total of 64K RAM. In most cases, you don’t want to inline code.

                If you only have limited program storage then inlining single use functions can help enormously! Reduced stack usage, dead code elimination, constant subexpression elimination, etc.

                As an example, I’ve enabled LTO to shrink a ~20KB ARM Thumb-2 firmware (-Os) down to fit into a part with 16KB of flash storage. (This is mostly due to vendor library abstraction layers that create a lot of nested function calls, but it shows there are potential big size reductions.)