Efficiency of development process using C versus 6502

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

User avatar
GradualGames
Posts: 1106
Joined: Sun Nov 09, 2008 9:18 pm
Location: Pennsylvania, USA
Contact:

Efficiency of development process using C versus 6502

Post by GradualGames »

So, I'm still pretty new to writing C for the NES. I keep feeling like it's actually going to wind up taking more of my time using it than if I just continue to build well-honed idioms in 6502. I also find myself feeling somewhat irritated with all the "noise" it generates. So much stuff going on that, I'm not sure if I really want to be bothered to fully understand. However, with regards to building full games with pure 6502, I really feel like I'm getting halfway decent at it at this point. I'm curious though if some of the C adherants here can vouch for it resulting in greater productivity whilst developing a game. I know I saw Shiru's video where he prototypes an object in Jim Power in C and then re-codes it in assembly. But...I have a feeling that adopting that process, for me personally will feel taxing, potentially. I may prefer to just continue to build games in 6502. Kinda hard to decide. It's kinda neat learning how one CAN write code in C on the NES, I'm enjoying that, but...not really sure if I'm gonna take the plunge and use it full tilt on my next project.

To put it in other terms, I suppose I feel like the power of abstraction that higher level languages offer would only really be useful if it was actually possible to forget about the hardware, with something really powerful like a modern PC or phone. On something as constrained as the NES, I'm just feeling like it's gonna get in the way. I mean....even with ca65 macros I got into hot water pretty quickly on my current project (code size grew much faster with them---thinking of specific use cases which were probably just bad design). I see headaches in my future if I use C. Haha.

*edit* One thing I thought of recently is, not too long ago I read about tokumaru's approach to enemy state machines essentially as continuations, obviating the need for annoying lists of state addresses and enums. It's something I'm looking forward to trying. I know one technically can fake this even in C, but...what is the point? It just seems like there are really good, really organized ways of coding in 6502 that can be just as fast (once you have enough practice) as developing in C.

*edit* Yet another thing I thought about was structures of arrays versus arrays of structures. C will always default to the latter (unless cc65 has a structures of arrays optimization I'm unaware of)? So if I code enemies in C first and then re-code them in assembly, I'm seeing two different entity update architectures being in place---one just for prototyping in C, and then one for the "real" 6502 implementation. This all just seems to be overkill.

Note, the speed to which I'm referring here is *development* speed, obviously C is always going to be slower actually executing.

Thoughts?
User avatar
dougeff
Posts: 3080
Joined: Fri May 08, 2015 7:17 pm

Re: Efficiency of development process using C versus 6502

Post by dougeff »

Why not take a hybrid approach...

Code 90% of the game in C, and any time you question how the C will compile (too many bytes, or too slowly) write that in ASM. You can call an ASM function from the C code.

(Of course I'm a newb at cc65 too). ;)
nesdoug.com -- blog/tutorial on programming for the NES
User avatar
tokumaru
Posts: 12536
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Efficiency of development process using C versus 6502

Post by tokumaru »

I personally haven't coded in C for the NES yet (and I don't really plan to), but from what I've read about it in here, it seems like you constantly have to monitor what your C code is compiling to in order to make sure it's not turning into a complete mess, which apparently happens quite often.

I think that having to check the assembly all the time kinda defeats the purpose, and I'd rather write good assembly from the get go, than stay stuck going back and forth until the C code becomes something acceptable. I imagine that the more you code in C, the more intuitive it gets, so you don't have to monitor the output as much, but I still don't know if it's worth the trouble.

I honestly don't think that coding in assembly is a chore, I actually like it a lot. I like the power of assembly, and being able to control every little detail of my programs. There are also all the little shortcuts you can take and tricks you can perform only with the freedom of assembly, and to me that's a big part of the fun.
User avatar
GradualGames
Posts: 1106
Joined: Sun Nov 09, 2008 9:18 pm
Location: Pennsylvania, USA
Contact:

Re: Efficiency of development process using C versus 6502

Post by GradualGames »

tokumaru wrote:I personally haven't coded in C for the NES yet (and I don't really plan to), but from what I've read about it in here, it seems like you constantly have to monitor what your C code is compiling to in order to make sure it's not turning into a complete mess, which apparently happens quite often.

I think that having to check the assembly all the time kinda defeats the purpose, and I'd rather write good assembly from the get go, than stay stuck going back and forth until the C code becomes something acceptable. I imagine that the more you code in C, the more intuitive it gets, so you don't have to monitor the output as much, but I still don't know if it's worth the trouble.

I honestly don't think that coding in assembly is a chore, I actually like it a lot. I like the power of assembly, and being able to control every little detail of my programs. There are also all the little shortcuts you can take and tricks you can perform only with the freedom of assembly, and to me that's a big part of the fun.
I think I'm leaning in this direction, having tried C out for a few weeks. I mean it is kinda neat that it's possible. I like high level languages most of the time, but on the NES, it's turning out to be a bit cumbersome. I really think you need power to match abstraction. I am curious about Shiru's thoughts on this though, since he apparently uses C to prototype things quickly and then re-codes in assembly. For me, I've occasionally written down some pseudo code in comments...which is almost the same process, just, you only have to get it working correctly once, in one language, rather than two :)
User avatar
rainwarrior
Posts: 8758
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Efficiency of development process using C versus 6502

Post by rainwarrior »

tokumaru wrote:...but from what I've read about it in here, it seems like you constantly have to monitor what your C code is compiling to in order to make sure it's not turning into a complete mess, which apparently happens quite often.
It will happen very often when you're starting out, for sure. Once you get used to what works well, it becomes less of a problem.

Nobody ever comes to the board to say "hey I wrote some C code and it's working like I expected it to", so if you're going by the stuff that comes up here, you're getting a bit of a bias toward its problems. :P
tokumaru wrote:I think that having to check the assembly all the time kinda defeats the purpose...
You don't need to check the assembly all the time. You need to check performance frequently. That's as easy as leaving a $2001 write at the end of your code to visually show you the frame's timing. Not really onerous at all, just leave that on while you're working, and run your code often.

You only have to look at the assembly if you want to gain a deeper knowledge of what the compiler is doing.
User avatar
rainwarrior
Posts: 8758
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Efficiency of development process using C versus 6502

Post by rainwarrior »

GradualGames wrote:Yet another thing I thought about was structures of arrays versus arrays of structures. C will always default to the latter (unless cc65 has a structures of arrays optimization I'm unaware of)?
Structure of arrays in C looks exactly like it sounds:

Code: Select all

// array of structures

struct Box {
    char a;
    char b;
    char c;
};

struct Box boxes[10];

boxes[5].c = 3;

// structure of arrays

struct Box {
    char a[10];
    char b[10];
    char c[10];
};

struct Box boxes;

boxes.c[5] = 3;
User avatar
GradualGames
Posts: 1106
Joined: Sun Nov 09, 2008 9:18 pm
Location: Pennsylvania, USA
Contact:

Re: Efficiency of development process using C versus 6502

Post by GradualGames »

What if you want to deal with 16 or 24 bit values? I might have an array of lo bytes and an array of hi bytes in my 6502 code, what I was wondering is if C can translate that into just an access of an array of ints. The point I'm trying to make is even in C code, you're still gonna have to have a lot of knowledge of the hardware and wrestle with it constantly. I'm not sure I'm convinced it can really help on such a constrained system. Probably in the end it boils down to how one enjoys working. To me, it's always a bit tough to get code to work correctly, I'd rather do that once...so...pseudocode for me. Haha.
User avatar
tokumaru
Posts: 12536
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Efficiency of development process using C versus 6502

Post by tokumaru »

Prototyping is good, and I'll certainly do it if it's something that can be tested in isolation. Coding two versions of the same program in parallel, however, is a bit too extreme in my opinion, and I'll probably never do that.

Generally, I try to write very well structured assembly code, with lots of comments, and I also try to do things in a consistent way every time. Another thing I do is separate the logic from the hardware interactions as much as possible. As long as I do those things, my assembly code is just as easy for me to follow as any other program I've written using high-level languages, so using C wouldn't make my programs any easier to comprehend.

Admittedly, engineering things in assembly might be a little harder, and prototyping helps you avoid wasting time engineering solutions around the wrong ideas. This is something I unfortunately have wasted some time on, since I don't have a simple easy to prototype more complicated ideas.
User avatar
tokumaru
Posts: 12536
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Efficiency of development process using C versus 6502

Post by tokumaru »

rainwarrior wrote:Nobody ever comes to the board to say "hey I wrote some C code and it's working like I expected it to"
Good point. I am picturing topics like that now though! :lol:
User avatar
dougeff
Posts: 3080
Joined: Fri May 08, 2015 7:17 pm

Re: Efficiency of development process using C versus 6502

Post by dougeff »

You only have to look at the assembly if you want to gain a deeper knowledge of what the compiler is doing.
I actually liked the way the C compiler does a few things. For 1, it seems to keep Y at zero, and anytime it needs a zero it can TYA (or STY). Another thing was this for incrementing a 16bit number... (I'm going from memory here).

Code: Select all

Ldx Highbyte
Lda Lowbyte
Clc
Adc #1
Bcc +
Inx
+sta lowbyte
Stx highbyte
This is about as efficiently you can do 16 bit math.
nesdoug.com -- blog/tutorial on programming for the NES
User avatar
rainwarrior
Posts: 8758
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Efficiency of development process using C versus 6502

Post by rainwarrior »

GradualGames wrote:What if you want to deal with 16 or 24 bit values? ... I might have an array of lo bytes and an array of hi bytes in my 6502 code, what I was wondering is if C can translate that into just an access of an array of ints.
I've never seen a C implementation with a 24 bit type. As for arrays of 16 bit values, yes you're probably out of luck. I will remind you, though, that striped organization of arrays is merely an optimization for efficiency, and you already gave up that efficiency to be using C in the first place. The extra cycles to put a *2 on the address aren't quite as bad as with larger structures.

If you mean you already have striped arrays in your efficient assembly part of the program, and you just want convenient access to them from the C part, perhaps just write some macros to make the fetching convenient?

Code: Select all

#define GET16(a,b,index) ((a[index]<<8)|b[index])
short int x = GET16(hi,lo,25);
I think cc65 is smart enough not to turn <<8 into 8 shifts, so it shouldn't do too badly with this. This method could also work with 24 bit striped arrays too (i.e. temporarily unpack them to a long int to work with them in C, then repack them when you're done).

If you mean you want to define the array as regular C code:

Code: Select all

short int array[10];
I don't think the C compiler would be allowed to "optimize" this as two striped arrays, even if it wanted to. I think it might be against the C specification (not entirely sure) for it to reorganize data that way.
GradualGames wrote:I'm not sure I'm convinced it can really help on such a constrained system.
I've written a bit of stuff in C on the NES, and I thought it was very much worthwhile. It made developing and iterating on the code significantly faster. There's no question in my mind about this.

It depends on what your goals are. I'm not using it for my current project, but that's largely because it's already being developed primarily in C++ / Win32. I don't really have to iterate on the NES assembly code much; it tends to port very easily once I have the details worked out in the C++ version. If the project was a little smaller in scope and didn't have the Win32 version, I'd probably be using C on the NES.
lidnariq
Site Admin
Posts: 11623
Joined: Sun Apr 13, 2008 11:12 am

Re: Efficiency of development process using C versus 6502

Post by lidnariq »

rainwarrior wrote:I've never seen a C implementation with a 24 bit type.
Unimportant tangent: I've seen this show up in several 8-bit microprocessor C compilers (e.g. HI-TECH PICC, where it is a short long) and at least one 8051 C compiler.
User avatar
GradualGames
Posts: 1106
Joined: Sun Nov 09, 2008 9:18 pm
Location: Pennsylvania, USA
Contact:

Re: Efficiency of development process using C versus 6502

Post by GradualGames »

Another thing which gives me pause about C coding is the issue of far calls. I've implemented a macro and routine which helps me turn any jsr into trampoline (and yes, I do preserve processor status for return values from far calls). As my game code began to sprawl multiple 16kb roms this became incredibly useful. Note I did not use this setup for high performance cases, in those cases I hard-code the trampoline. I suppose I'm concerned if I take the plunge into C and make something as large as my current project, I'm going to have a lot of really inefficient far-calling going on (probably much worse than this macro and routine I wrote for 6502 far calls). The sprawl I am guessing will be dramatically worse than plain 6502 code.

I'm also not exactly sure how I'd structure a game program. I like that in 6502 I can simply jump to another location intended for initializing a new game state, without modifying the stack. I'm sure I could just split it up into functions and use a switch case or what not...I dunno. I'm probably just wrestling with an overall resistance to change. Hey at least I'm trying it out. Haha

*edit* I thought of what you're suggesting Rainwarrior, write some utility macros to pull the bytes out of my arrays to rearrange them into 16 bit values etc. But it just feels hacky, in my mind.

I use 24 bit values all the time. 16 bit world coordinates and 8 bit sub-pixel precision. It feels really natural to work with. How would one work with these in C? With longs?
User avatar
rainwarrior
Posts: 8758
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Efficiency of development process using C versus 6502

Post by rainwarrior »

GradualGames wrote:Another thing which gives me pause about C coding is the issue of far calls.
CC65 has no far call capability, and that's more or less something that would have to be built into the language. You can write assembly trampolines, and call them from C if you like, but there's just no language support for a C to C far call.

There are C compilers that have their own extensions for far calls (e.g. x86 compilers before the 386), but CC65 has no such extension. Far calls are not part of the ANSI C standard, so this is always a compiler-specific thing. In this case you'd really need not just a NES-aware C compiler (which CC65 is not), but an NES C compiler with a specific mapper in mind.

There's a few of us here who have taken a liking to BNROM's 32k banking, which would give you a lot more space to fit all your C code into a single bank (though confining the C code to two 16k banks, one fixed, one bankable, would be just as good, I suppose). Putting C code in more than one bank is somewhat possible, but it wouldn't be easy. Much easier to keep all your C in one bank, and any "far" calls would go to pure assembly.
GradualGames wrote:But it just feels hacky, in my mind.
I'm usually more concerned with what code does, and how easy it is to write or change, than how it "feels". Nobody playing your game will be able to feel your code. ;)
GradualGames wrote:I use 24 bit values all the time. 16 bit world coordinates and 8 bit sub-pixel precision. It feels really natural to work with. How would one work with these in C? With longs?
Yes, I would probably temporarily convert them to 32 bit integers to work with them in C, or 16 bit integers if the particular routine was not interested in sub-pixel precision.
User avatar
Bregalad
Posts: 8104
Joined: Fri Nov 12, 2004 2:49 pm
Location: Divonne-les-bains, France

Re: Efficiency of development process using C versus 6502

Post by Bregalad »

Honnestly to this point I tend to belive the best option is to prototype the full game in any high level language (not necessarly) on a less limited platoform, and port it to assembly and NES hardware as a second step.

I also think other high level languages might be more suited to the 6502 than ANSI C (I could be wrong).
Post Reply