Jump to content
IGNORED

Taking advantage of C++17 to build 6502 code


jmccorm
 Share

Recommended Posts

Jason Turner demonstrates the features of a modern C++ compiler by creating a simple game for the Commodore 64 by passing the compiler's native output through an x86-to-6502 conversion tool. (He also explains why he has gone with this approach instead of modifying the compiler to directly target the 6502.)

 

The amount of optimization that he gets from a modern C++ compiler (both due to advancements in compiler design as well his knowledge on how to take advantage of its specific features) is absolutely astonishing. Complicated and nested functions are evaluated a compile-time and reduced to a minimal number of optimized machine language operations.

 

This sort of thing may not be appropriate applications with critical timing (like mid-line DLI changes), but it is inspiring to use this approach to create the bulk of a program for the 6502. Any thoughts?

 

https://www.youtube.com/watch?v=zBkNBP00wJE

Link to comment
Share on other sites

Neat hack, but no, you really don't want to use this.

The 6502 already isn't great at C because of its weaknesses in handling pointers and 16-bit arithmetic, on which C is heavily dependent. C++ makes this worse because of its additional features that rely heavily on the optimizer to generate good code. Reliance on the optimizer means lack of guarantees. On a modern CPU, if a function fails to be inlined or a copy is not optimized out in a commonly used code path, the code runs a bit slower. On a 6502-based machine, this can easily be fatal because of excessive code bloat. It's cool that you could use zero-cost stuff like constexpr, but large portions of the language like virtual methods, exceptions, RTTI, and the standard template library would still be inadvisable. And you still don't have features in the base language that are critical for 6502 code, such as the ability to place code and data at absolute addresses.

On top of that, the sample code has fugly stuff like this:

 *reinterpret_cast<uint8_t*>(53280) = 1;

This is not exactly the appealing side of "modern C++," and you'd be doing this a lot on an 8-bit platform.

  • Like 7
Link to comment
Share on other sites

When you write code for 6502 everyone knows no automatized generator of code can be so good as a human in special for 6502.

 

And when you're writing for 4K or 8K, simply any wasted byte is a pain.

 

Batari BASIC is good because the BASIC language translates more easily to 6502 and almost without requiring runtimes, here wasting a byte is compensated by the fact of easier coding.

 

But using C++17 is essentially overkill and only good for a "I did it, it's not so useful but I did it".

 

If you want to get some performance of it you'll end coding like in BASIC, inside the main function almost with only if and gotos.

  • Like 2
Link to comment
Share on other sites

When you write code for 6502 everyone knows no automatized generator of code can be so good as a human in special for 6502.

 

And when you're writing for 4K or 8K, simply any wasted byte is a pain.

 

If you want to get some performance of it you'll end coding like in BASIC, inside the main function almost with only if and gotos.

 

In essence, this is true. Yet it's the mission (impossible?) for good compilers to keep challenging the statement #1.

  • Like 2
Link to comment
Share on other sites

Something like this has a very good use for certain genres:

  • turn-based games
  • strategy games
  • RPG games (even real-time, just not twitch-reflex real-time ones)
  • Dungeon Crawlers
  • Large-scale Universe (e.g. Elite)

 

Some prerequisites:

  • Bank-Switching from extended RAM (at the very least 0.5 MB, though I'd argue how much 6502 C++ code can you really cram under less than 1 MB)
  • Rendering code written in ASM
  • The Transition Layer between ASM and C++, that will handle fast copying of data from the C++ classes (without dozen layers of syntactic sugar)

 

Why would anyone want to use C++ on 6502 ?

  • Extremely fast gameplay prototyping
  • C++ allows you to compose behavioral sentences from within the code that would take complex and bug-prone if/else cascades
  • You are not concerned with throwing away the code for feature that does not turn out to be much fun
  • You can literally write full complex game in few days (don't confuse with level design) - something that is simply impossible to debug from ASM

 

I mentioned the very same idea in my flatshading thread earlier last year and it's one of my long-term goals towards which I want to eventually converge over the course of next several years.

 

Now, I haven't seen a 6502 code for some neat C++ 17 features.

 

I did, however, see a lot of C code compiled to Motorola 68000 ASM on Atari Jaguar 2 yrs ago, and that was a bloody disaster, as what the compiler does with the simplest things like structures, is just mind-boggling...

  • Like 2
Link to comment
Share on other sites

I finished watching the video today and I am quite disappointed:

- the initial impression was that someone was involved in creating a G++ target for 6502, which is obviously not true, as he merely translates the x86 code into 6502 (there's not that many instructions used for that example)

- the whole game is basically just manipulating system registers, so to keep praising the C++17 "how smart it is" that it doesn't put bloat around storing a value into a pointer, is plain ridiculous

 

- those C++17 features is the last thing from C++ that you actually need to access mere memory registers, it'd be incredibly cumbersome and counterproductive to use that stupid syntax just to do POKE/PEEK

- there's half a dozen other WTFs (RGB colors ? Really ?!?), but best if everyone finishes the whole video for themselves

 

- even C with classes is an order of magnitude more productive for gameplay coding than the nonsense in the video

 

 

I still stand behind my reasons why to use C++ on 6502 in my previous post. Unfortunately, none of those points were addressed in that presentation.

  • Like 3
Link to comment
Share on other sites

Using volatile, const and static in C for embedded systems is pretty common practice. You want hardware registers to be treated volatile so no store or load gets optimized away. Otherwise, I totally agree with you all. All his function calls get inlined. Wait until that isn't possible and his x86-to-6502 translator has to handle stack frames and relative addressing...

 

On the other hand, using C or C++ for rapid prototyping, timing and testing, and generating 6502 code on-the-fly is something entirely different. As VladR points out, this can be extremely helpful.

Link to comment
Share on other sites

There's a (relatively) new gcc backend:

 

https://github.com/puppeh/gcc-6502

 

Uses page zero as a bunch of 32-bit registers, of which the 16 least significant bits can directly be dereferenced as a pointer. And even A, X and Y are treated as 32-bits (all of them, including the 24 missing bits are also located at zero page). But stack relative is still a problem. A pointer on the stack has to be moved to a "register" before it can be dereferenced.

Edited by ivop
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...