Efficiency of development process using C versus 6502
Moderator: Moderators
- GradualGames
- Posts: 1106
- Joined: Sun Nov 09, 2008 9:18 pm
- Location: Pennsylvania, USA
- Contact:
Efficiency of development process using C versus 6502
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?
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?
Re: Efficiency of development process using C versus 6502
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).![Wink ;)](./images/smilies/icon_wink.gif)
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).
![Wink ;)](./images/smilies/icon_wink.gif)
nesdoug.com -- blog/tutorial on programming for the NES
Re: Efficiency of development process using C versus 6502
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 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.
- GradualGames
- Posts: 1106
- Joined: Sun Nov 09, 2008 9:18 pm
- Location: Pennsylvania, USA
- Contact:
Re: Efficiency of development process using C versus 6502
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 twotokumaru 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.
![Smile :)](./images/smilies/icon_smile.gif)
- rainwarrior
- Posts: 8758
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: Efficiency of development process using C versus 6502
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.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.
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.
![Razz :P](./images/smilies/icon_razz.gif)
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.tokumaru wrote:I think that having to check the assembly all the time kinda defeats the purpose...
You only have to look at the assembly if you want to gain a deeper knowledge of what the compiler is doing.
- rainwarrior
- Posts: 8758
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: Efficiency of development process using C versus 6502
Structure of arrays in C looks exactly like it sounds: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)?
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;
- GradualGames
- Posts: 1106
- Joined: Sun Nov 09, 2008 9:18 pm
- Location: Pennsylvania, USA
- Contact:
Re: Efficiency of development process using C versus 6502
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.
Re: Efficiency of development process using C versus 6502
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.
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.
Re: Efficiency of development process using C versus 6502
Good point. I am picturing topics like that now though!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"
![Laughing :lol:](./images/smilies/icon_lol.gif)
Re: Efficiency of development process using C versus 6502
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).You only have to look at the assembly if you want to gain a deeper knowledge of what the compiler is doing.
Code: Select all
Ldx Highbyte
Lda Lowbyte
Clc
Adc #1
Bcc +
Inx
+sta lowbyte
Stx highbyte
nesdoug.com -- blog/tutorial on programming for the NES
- rainwarrior
- Posts: 8758
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: Efficiency of development process using C versus 6502
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.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.
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);
If you mean you want to define the array as regular C code:
Code: Select all
short int array[10];
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.GradualGames wrote:I'm not sure I'm convinced it can really help on such a constrained system.
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.
Re: Efficiency of development process using C versus 6502
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.rainwarrior wrote:I've never seen a C implementation with a 24 bit type.
- GradualGames
- Posts: 1106
- Joined: Sun Nov 09, 2008 9:18 pm
- Location: Pennsylvania, USA
- Contact:
Re: Efficiency of development process using C versus 6502
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?
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?
- rainwarrior
- Posts: 8758
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: Efficiency of development process using C versus 6502
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.GradualGames wrote:Another thing which gives me pause about C coding is the issue of far calls.
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.
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:But it just feels hacky, in my mind.
![Wink ;)](./images/smilies/icon_wink.gif)
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.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?
Re: Efficiency of development process using C versus 6502
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).
I also think other high level languages might be more suited to the 6502 than ANSI C (I could be wrong).