Live data from Hacker News

How to program an NES game in C

nesdoug.com

61–70 of 70 posts

Re: How to program an NES game in C

#61
post #22

Earlier quoted context omitted.

From that page, "use ++g instead of g++ (it’s faster)" I've seen people say this a repeatedly when talking about "embedded" environments, but never understood why - won't it end up compiling to the same thing either way?

Depends on the compiler. 'a++' (postfix) and '++a' (prefix) have slightly different meanings in terms of return values. Postfix will return the value of 'a' before the increment, while prefix will return 'a' after the increment operation. In a simple compiler, you would store the previous value of 'a' in the case of postfix in case you need to assign it. This results in a superfluous store instruction in most cases.…

I’ve used crappy compilers where there’s essentially no optimisation, and moderately complex expressions produce absurd code, so if you want reasonable output, you end up writing the assembly you want in the notation of the higher-level language, like:

    /* a = (b * 2) + 1 */

    a = b;    /* mov a, b */
    a 

Re: How to program an NES game in C

#62
post #55

Earlier quoted context omitted.

Didn't John Carmack use structures rather than parallel arrays even in Apple II assembly? Source: one of his old .plan files, reproduced verbatim in _Masters of Doom_ Edit: Found it online here: https://github.com/ESWAT/john-carmack-plan-archive/blob/mast...

I wrote a few lines about 6502 vs Z80 a couple of years ago: https://news.ycombinator.com/item?id=10766264 (parent of linked-to comment may also be of interest) - the discussion there was about relative efficiency of the two CPUs, but the addressing mode limitations that make one approach a bit inefficient on the 6502 are the same limitations that make it a bit inconvenient. I wonder what Carmack had in mind. --- P.S…

Asked to see if someone speaks up

https://stackoverflow.com/questions/45667636/advantages-of-a...

Re: How to program an NES game in C

#63

Earlier quoted context omitted.

Does c65 turn structs into parallel arrays? If you have something like struct Monster { unsigned char hitPoints; unsigned char damage; unsigned char shieldLevel; char* name; }; static Monster s_monsters[] = { { 5, 1, 0, "orc", }, { 50, 10, 5, "dragon", }, { 10, 3, 1, "goblin", }, }; that's a no-no on 6502. You generally need to store those in parallel byte arrays including the string pointer's upper and lower bytes e…

cc65 has a whole page on how to deal with the fact that it's a single-pass compiler with hardly any optimization [1]. It's almost more like a macro assembler than an actual compiler. http://www.cc65.org/doc/coding.html

Then again, I managed to compile the code for the crypto hash Blake2s with it, producing code that validated all of the (few) test vectors I threw at it, so whatever expectations one might have on "actual compilers", for me, cc65 does fulfil a lot of them.

Re: How to program an NES game in C

#64
post #46
post #36

> All NES assembers are command line programs. What does that mean? It has no graphic user interface. Who the hell is this written for?

I find a lot of these homebrew and ROM hacking documents are written for an enthusiast that might not necessarily have a background in software development. At first I found it a little disorienting because the technical level of the writing would fluctuate, but at the same time I can appreciate it being accessible for someone who might not know much about programming.

I used to dabble a lot in homebrew programming for PSP(playstation portable) and many people would be shocked how much of the entire toolchain was made by people with little if any formal programming education - yet it all worked and produced valid executables. I suspect a lot of it was done by other 15-year old teenagers experimenting with low level programming for the first time.

Re: How to program an NES game in C

#65
post #45
post #8

Earlier quoted context omitted.

Might be easier (but just as much fun) to whet your palate by creating a pico-8 game first: https://www.lexaloffle.com/pico-8.php

I'd beg to differ. Interpreted lua on a 4GHz pc with 4G of ram is not like compiled C on a 8bit micro. Avr dev or arduino could be arguably closer.

remember that pico-8 is a very limited fantasy console and only has:

32KB cartridges

32KB RAM

a 1MB RAM limitation for the lua VM

Re: How to program an NES game in C

#66

IMHO a 6502 is too limited to be effectively programmed in C; even this part of the article gives all the limitations: https://nesdoug.com/2015/11/15/2-how-cc65-works/ With this important note: "clean unaltered C code will compile into very slow code that takes up too much of the limited memory space." In other words, "C" written for such a CPU will be in a vastly different style from more "normal" C, so that it migh…

Does c65 turn structs into parallel arrays? If you have something like struct Monster { unsigned char hitPoints; unsigned char damage; unsigned char shieldLevel; char* name; }; static Monster s_monsters[] = { { 5, 1, 0, "orc", }, { 50, 10, 5, "dragon", }, { 10, 3, 1, "goblin", }, }; that's a no-no on 6502. You generally need to store those in parallel byte arrays including the string pointer's upper and lower bytes e…

I don't think it does, and I don't think it's possible to make a nearly standards compliant C compiler that does. A struct is a contiguous piece of memory, which makes things like memcpy and malloc generally possible.

Re: How to program an NES game in C

#67
post #3

IMHO a 6502 is too limited to be effectively programmed in C; even this part of the article gives all the limitations: https://nesdoug.com/2015/11/15/2-how-cc65-works/ With this important note: "clean unaltered C code will compile into very slow code that takes up too much of the limited memory space." In other words, "C" written for such a CPU will be in a vastly different style from more "normal" C, so that it migh…

I feel like handling ROM banking would be the most challenging part of coding in C. You have to swap portions of your program in and out constantly (unless you manage to fit it all in a single bank). It seems hard to abstract that efficiently from a high level language. I heard there were C compilers for the Game Boy as well but as far I know they were never widely used.

I believe that cc65 has a good linker that handles once set up for a platform/memory configuration. I don't know how efficient it is, but I bet that manually organizing code and data to minimize cross-page access will be more efficient.

On old (16-bit) x86 you used "far" pointers, which were larger for cross segment access. These were larger and I assume slower since they encoded both the within-segment address and the segment number.

Re: How to program an NES game in C

#68

IMHO a 6502 is too limited to be effectively programmed in C; even this part of the article gives all the limitations: https://nesdoug.com/2015/11/15/2-how-cc65-works/ With this important note: "clean unaltered C code will compile into very slow code that takes up too much of the limited memory space." In other words, "C" written for such a CPU will be in a vastly different style from more "normal" C, so that it migh…

> IMHO a 6502 is too limited to be effectively programmed in C

I've had some thoughts on this before and I think it boils down to the requirements. Beyond the obvious (the speed and memory requirements for your application):

If a 256 byte separate data stack is large enough, and particularly if you can put that all in zero page you can save many cycles. Then you can use the X index register as a stack pointer, benefiting from shorter and faster zero page indexed addressing for stack-relative loading and storing and using values on the stack directly for indirection using the indirect addressing modes without first copying stuff to zero page.

That's not to say that Z80 isn't a much better target for a C compiler. Among 16-bit 6800-likes, 6809 doesn't seem half bad, though.

Re: How to program an NES game in C

#70
post #22

Earlier quoted context omitted.

Depends on the compiler. 'a++' (postfix) and '++a' (prefix) have slightly different meanings in terms of return values. Postfix will return the value of 'a' before the increment, while prefix will return 'a' after the increment operation. In a simple compiler, you would store the previous value of 'a' in the case of postfix in case you need to assign it. This results in a superfluous store instruction in most cases.…

I’ve used crappy compilers where there’s essentially no optimisation, and moderately complex expressions produce absurd code, so if you want reasonable output, you end up writing the assembly you want in the notation of the higher-level language, like: /* a = (b * 2) + 1 */ a = b; /* mov a, b */ a

TI used to have an Assembler that was exactly like that, don't recall for which processor though.
Post reply on HN