This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

KNES library for CC65 (aka Programming the NES in C)

KNES library for CC65 (aka Programming the NES in C)
by on (#69141)
This is a replacement NES library for CC65, somewhat alike to rNES. I have removed bunch of “useless” stuff from the default nes.lib and replaced crt0.s with a new version. There's also a platformer demo with source.

Get it from http://kkfos.aspekt.fi/projects/nes/kne ... -for-cc65/

Any comments and suggestions are welcome.

by on (#69209)
Hey, that's really neat. Hopefully someone will use it for something cool. At the very least perhaps it could help make learning the NES a little easier for some people. They could start with C and then gradually migrate to replacing their C code with asm, perhaps. I know for me I'm so used to asm I don't think I'll need to use C...but it is still neat that it is now proven it is possible to write a decent game for the NES in C. Good work. I'm assuming the demo is similar to the C platformer demo you posted a while ago?

by on (#69212)
Gradualore wrote:
Hey, that's really neat. Hopefully someone will use it for something cool. At the very least perhaps it could help make learning the NES a little easier for some people. They could start with C and then gradually migrate to replacing their C code with asm, perhaps.

Yeah, that was one of the goals. Hopefully it brings more people to the homebrew scene. Nerdy Nights style programming tutorial for C could work really well. :)

It's funny to think that the bulk of the currently released homebrew games could have been written in C... (well, it's mostly puzzle games anyways).

Gradualore wrote:
I know for me I'm so used to asm I don't think I'll need to use C...but it is still neat that it is now proven it is possible to write a decent game for the NES in C. Good work. I'm assuming the demo is similar to the C platformer demo you posted a while ago?

Yeah, the demo is almost exactly the same. I simply added a few more features and fixed a couple of things. It's not still a full game but there's plenty of CPU time to add features (especially if the music engine is replaced with one written in assembly).

I actually quite like writing NES stuff in C. I'm probably going to write some of the less speed critical parts of my WIP game in C, like menus and cut scenes.

Also I think it can be useful for prototyping algorithms. Of course it's possible to use something like SDL for the same purpose (and I have done so in the past) but at least I have another option now. :) It's much less error prone than writing the same stuff in asm, IMO.

by on (#69214)
If it's good enough for Koei...

by on (#69245)
I've always wanted to program the NES in basic....even through an interpreter. Maybe there is some way to use BASIC compiled into assembly for the NES? -pokes all the 1980's Basics-


And seeing the performance hit for C on a NES.....I think it's just too insane. 6K cycles for only a few commands? Ickkk.....and anyone who knows C should be able to pick up assembly IMO. I think if we were to make a programming language people who can't program could make stuff with, I don't think C would be the answer..... :/

by on (#69248)
65024U wrote:
I've always wanted to program the NES in basic

Family BASIC exists. It was never ported to NES because the keyboard wasn't brought over. In fact, as I understand it, there is still no standard keyboard for the 72-pin NES, nor an adapter for PS/2 or USB keyboards. If there were one, I'd probably have made something years ago.

by on (#69249)
65024U wrote:
And seeing the performance hit for C on a NES.....I think it's just too insane. 6K cycles for only a few commands? Ickkk.....and anyone who knows C should be able to pick up assembly IMO.

Now I don't want to come out too defensive, you're entitled to your opinion, but I don't agree with you.

1) You're refering to the figures I posted at NintendoAGE? I don't know where you get "only a few commands" from... The code checks controller state, updates sprites, physics and checks collisions in update_frame(), hardly "only a few commands". Also there is room for (algorithmic) optimization.

2) Even if there IS a performance hit (of course there is compared to assembly, unless the assembly is programmed really poorly), it doesn't matter UNLESS it matters. What I'm trying to say, it doesn't matter how much CPU time it uses if it does the job in time. Premature optimization is the root of all evil.

3) "and anyone who knows C should be able to pick up assembly".. but assembly isn't C. C code is more maintainable, more readable, faster to code etc etc. To put it short, I think you're missing the point.

by on (#69251)
It's great to see a C library released for the NES.
I didn't look into it, but it sounds all good to me. Saying the performance hit isn't worth the trouble coding in C before even trying is now a good engineering approach. You'd want to at least try to code a game in C, and if it's too slow, port it to assembly, if still too slow port it to a faster system :)

What you guys seems to be forgetting is that it's perfectly possible to mix assembly and C in the same project. So in a typical case, you'd do tight loops that are executed often in assembly, and complex code that isn't executed often in C. Typically :
- Interrupts
- Sprites mazing
- Scroll updates
- Controller reading
- Music engine

Must be done in assembly. For game logic, it's probably not much of a performance hit if you write it in C. I might be wrong, but without trying you can't know.

Oh and of course you have to reserve an argument stack which is a bit annoying and will eat RAM... but maybe this will kill some bugs. I've had so many bugs in assembly because of variable conflicts, especially with TempX or whatever general purpose variables.

PS : A major problem though is that th most you use "tricks" to make C more optimized, like using static variables instead of parameters, the most it will end up complex to read and understand as ASM, so in the end you'd as well use ASM.

by on (#69254)
Bregalad wrote:
PS : A major problem though is that th most you use "tricks" to make C more optimized, like using static variables instead of parameters, the most it will end up complex to read and understand as ASM, so in the end you'd as well use ASM.

This is definitely true (I assume you meant global variables). Also looking at the C generated assembly listing for hours trying to figure out ways to make the C code more optimized can end up taking more time than writing the same thing in ASM, and can defeat the purpose of using C. But oh well. :)

by on (#69255)
I think this is a great thing! To me great thing about it is it provides and easier starting point for those just new to NES development. Naturally when they reach the limitations of C code they will be forced to move on the ASM, and by that point they should understand enough that it won't be seemingly impossible. I know I just about gave up when I fist looked at it.

by on (#69260)
If you provide a library that contains useful reusable routines that do significant work, the C code can do the light-duty stuff and thus not need to be as efficient. For example, you might have an asm routine that does sprite DMA, and copies tens of bytes to VRAM quickly in VBL, and make it usable from C.

by on (#69261)
thefox wrote:
65024U wrote:
And seeing the performance hit for C on a NES.....I think it's just too insane. 6K cycles for only a few commands? Ickkk.....and anyone who knows C should be able to pick up assembly IMO.

Now I don't want to come out too defensive, you're entitled to your opinion, but I don't agree with you.

1) You're refering to the figures I posted at NintendoAGE? I don't know where you get "only a few commands" from... The code checks controller state, updates sprites, physics and checks collisions in update_frame(), hardly "only a few commands". Also there is room for (algorithmic) optimization.

2) Even if there IS a performance hit (of course there is compared to assembly, unless the assembly is programmed really poorly), it doesn't matter UNLESS it matters. What I'm trying to say, it doesn't matter how much CPU time it uses if it does the job in time. Premature optimization is the root of all evil.

3) "and anyone who knows C should be able to pick up assembly".. but assembly isn't C. C code is more maintainable, more readable, faster to code etc etc. To put it short, I think you're missing the point.


As someone with many years of experience in both C and asm, I have to agree 99% with thefox's three points. Being able to program in pure asm has a certain "coolness factor" to it. However, pure asm is not always the right answer. There are different tools and different jobs. Sometimes several tools are equally valid choices, and sometimes only one tool will do (and sometimes no tools work).

My only issue is with "pre-mature optimization". Some people (ok, my former boss) are militant about deferring optimization until really late. The problem is that by then the project becomes too difficult to optimize (sometimes). Choosing proper data structures at the beginning will go a long way to ensuring that your project will be optimal enough later. For my personal projects I tend to profile, optimize and refactor my code many times as I develop it. If nothing else, I'll make it crunch a large data set while running inside a profiler so that at least I know where it is spending its time.

That being said, I still have not experimented with using C (or any other high-level language) in a NES project. I liked the idea of NESHLA, but I did not like its implementation or syntax. I write all of my asm in ca65, so throwing in cc65 should not be too difficult.

by on (#69264)
Haha sorry, I didn't want to make it explode. I think this is really cool, but shouldn't it be more for newbies? This is very cool and worth looking into, but still.....wouldn't a BASIC-type OS that also could translate to 6502 ASM on the same system work a bit better then C?



I am just thinking....If you could make a BASIC interpreter that at the end of development, be assembled to assembly? Or atleast include C functions that are smaller and do less so you don't have to call whole functions, because the less you can do per instruction, the more you can add and customize.



And wasn't there a C compiler from some game company? We need to contact them! :lol:


I'll probably mess with this later....If the weekend ever gets here.

by on (#69267)
Great demo. Pretty cool to see the source for an NES program, coded in C. I think I will use C for some things on NES, and having a base to start with helps. I've been doing asm for years, but C is new to me.

65024U: There is one BASIC compiler I'm aware of - nbasic. But you're sure to need inline assembly with this. A BASIC interpreter would be cool, Family BASIC seems good enough to use though.

by on (#69268)
65024U wrote:
wouldn't a BASIC-type OS that also could translate to 6502 ASM on the same system work a bit better then C?

Work better in what sense? :) I think it's bit of an apples and oranges situation...

by on (#69271)
thefox wrote:
65024U wrote:
wouldn't a BASIC-type OS that also could translate to 6502 ASM on the same system work a bit better then C?

Work better in what sense? :) I think it's bit of an apples and oranges situation...



Well....compile better. Because basic would need more commands, but each one would translate into less instuructions and allow for more editable code to be written, not running whole functions and such....but what do I know. I just know TRS-80 basic isn't too bad! :P



I'm going to have to get into this some time....and the hit detection would be nasty to write in BASIC I guess....maybe this would be alot better? Anyway this is really cool.

by on (#69274)
Then perhaps we need a scripting language with specialized data types for games. These might include points and rectangles, where operator AND performs intersection: rect AND point returns true iff point is within rect, and rect AND rect returns their intersection. Then hit detection would be a matter of computing two objects' hitboxes and ANDing them together.

by on (#69280)
Well, not need...but like that.....more lightweight functions. The C program can do it though so maybe this'll get easier like basic as it goes, who knows? :P

by on (#69284)
Another issue with C is debugging. If you have a bug in your C code, it will be harder to find in FCEU's debugger than if you did an error in your assembly code.

by on (#69285)
Bregalad wrote:
Another issue with C is debugging. If you have a bug in your C code, it will be harder to find in FCEU's debugger than if you did an error in your assembly code.


Great point. I have a hard time understanding my assembly. I'd hate to run through a compilers! :shock:

by on (#69286)
Bregalad wrote:
Another issue with C is debugging. If you have a bug in your C code, it will be harder to find in FCEU's debugger than if you did an error in your assembly code.

http://nesdev.com/bbs/viewtopic.php?t=6773

Works fine with C sources too. I'm not sure about the version posted there but I have it working here...

by on (#69299)
Any debugger that allows importing a file with labels and comments can in theory be used for source-level debugging.

by on (#74659)
Hey, this demo is awesome, and really got me moving on getting some NES development started. I'm learning a lot, and having a completed demo like this with player movement, scrolling, and collision is fantastic. I'll probably make a thread in the new users forum soon with specific questions about getting things to happen in this demo, things like how do I generate new levels for this, or how do I fully implement left scrolling.

by on (#75125)
Greetings, I am having trouble getting knes working - I'm sure it's something simple that I'm overlooking. My process so far has been:
* Install cc65 from the latest snapshot, set up w/ env variables etc
* Copy nes.lib from cc65 into knes/original, make knes
* Copy knes.lib and knes.h, nes-nrom.cfg into appropriate folders
* Edit nes-nrom.cfg as per this post
* Copy header.h and header.c to my project directory
* Attempt to compile my project:
Code:
//HAI2.c

#include "conio.h"
#include "knes.h"

int main(void) {
   clrscr();
   cprintf("OHI");
   while(1) {}
   return 0;
}


Code:
cl65 -t none -C nes-nrom.cfg -o HAI2.nes HAI2.c header.c knes.lib
Unresolved external `_clrscr' referenced in:
  HAI2.s(14)
Unresolved external `_cputc' referenced in:
  vcprintf.s(9)


Any ideas as to what I'm missing?

by on (#75130)
dirtyHippy wrote:
Code:
//HAI2.c

#include "conio.h"
#include "knes.h"

int main(void) {
   clrscr();
   cprintf("OHI");
   while(1) {}
   return 0;
}

KNES doesn't support conio.h routines, sorry. :) If you want to print something you have to write directly to PPU via PPU_ADDR() and PPU.data.

by on (#75133)
thefox wrote:
KNES doesn't support conio.h routines, sorry. :) If you want to print something you have to write directly to PPU via PPU_ADDR() and PPU.data.
I knew it was something simple :). Thanks for the quick reply

by on (#75182)
Hey it's great to see someone picked up the idea!
Keep it up!

by on (#75210)
cool.. too bad my c is so rusty

by on (#78664)
Posted version 0.1.1 in the website (see first post) to fix problems which were discussed in this thread. In other words it now works with the latest dev version of CC65...

by on (#78947)
Looked at the game demo and its sources, it is really cool. Haven't expected scrolled map engine in C with fullspeed. Especially was impressed with music engine also written in C.

by on (#81972)
thefox wrote:
Posted version 0.1.1 in the website (see first post) to fix problems which were discussed in this thread. In other words it now works with the latest dev version of CC65...


Hi thefox,

I've tried with the latest version (snapshot from 2011-07-18), but cannot get it to work, I always get this:



Code:
C:\Nes\knes-0.1.1\knes>make
cl65 -v -g -t none -c crt0.s
cl65 -t none -g -T -Cl -Oirs -c knes.c
cl65 -v -g -t none -c _read_joy.s
copy original/nes.lib knes.lib
original\nes.lib
        1 arquivo(s) copiado(s).
ar65 d knes.lib _scrsize.o cclear.o chline.o clock.o clrscr.o color.o cputc.o cr
t0.o cvline.o get_tv.o gotox.o gotoxy.o gotoy.o mainargs.o ppu.o ppubuf.o random
ize.o revers.o setcursor.o sysuname.o waitvblank.o wherex.o wherey.o
ar65.exe: Error: Read error (file corrupt?)
mingw32-make: *** [knes.lib] Error 255


Any ideas?

by on (#81973)
kbessa wrote:
I've tried with the latest version (snapshot from 2011-07-18), but cannot get it to work, I always get this:

I think the object file version has been changed again, try replacing "original/nes.lib" with nes.lib from this package: ftp://ftp.musoftware.de/pub/uz/cc65/sna ... 0718-1.zip

Then delete knes.lib and all .o files and run make.

EDIT: Actually there's also other problem. You changed "cp" to "copy" in the Makefile, so you need to change the forward slash to backward slash or it won't work properly. Change to: copy original\nes.lib knes.lib

by on (#81974)
thefox wrote:
I think the object file version has been changed again, try replacing "original/nes.lib" with nes.lib from this package: ftp://ftp.musoftware.de/pub/uz/cc65/sna ... 0718-1.zip

Then delete knes.lib and all .o files and run make.

EDIT: Actually there's also other problem. You changed "cp" to "copy" in the Makefile, so you need to change the forward slash to backward slash or it won't work properly. Change to: copy original\nes.lib knes.lib


Yep, I already had replaced the nes.lib, and had to change cp to copy as it was not being recognized (I'm compiling on Windows).

But yeah, changing to a backward slash solved it, was able to make knes.lib and also to rebuild the demo project, it loaded fine in FCEUX 2.1.5. Thanks!

by on (#82009)
Could we put together some sort of optimization guide for your C code? For instance, I've noticed that this code:

Code:
someStruct.x[idx] = someStruct.y[idx];


results in a subroutine call with a *lot* of pointer math, whereas this code:

Code:
temp = someStruct.y[idx];
someStruct.x[idx] = temp;


does not.

What other best practices do you all know of?

by on (#82014)
qbradq wrote:
Could we put together some sort of optimization guide for your C code? For instance, I've noticed that this code: ... results in a subroutine call with a *lot* of pointer math, whereas this code: ... does not.

Does this happen with or without optimization switches (or both)?

My basic set of tips is listed on my homepage (http://kkfos.aspekt.fi/projects/nes/knes-library-for-cc65/):

1) -Cl switch to make local variables static
2) #pragma bss-name/data-name to set the bss-/data-segment to zeropage
3) __fastcall__ calling convention for faster parameter passing
4) -Oirs
5) Avoid interleaved data

by on (#82018)
I found your tips very informative. I was very happy to see the "force static locals" flag.

This is using the same compiler flags as your demo make file. Here's the code I used:

Code:
struct
{
  int x[16];
  int y[16];
  byte flags[16];
} objects;

int main(void)
{
  static byte a;
 
  for(a = 0; a < 16; ++a)
  {
    objects.x[a] = objects.y[a];
  }
  return 0;
}

by on (#82040)
Could someone give me an example of implementing a function in pure assembly with accesses to arrays and structs defined in C?

by on (#82041)
Arrays are available as pointers (16-bit absolute addresses), structs - I don't know, haven't used them yet.

Simplest form of access to an array:

Code:
;void __fastcall__ func(const unsigned char *array);

_func:
 ;A:X is the pointer to array (LSB,MSB)
 rts

by on (#82043)
Great! That helps a lot Shiru, thanks! So the name of the label needs to be preceded by an underscore for C to be able to see it? And I don't need to back anything up (like registers)?

I'll play around with this a bit when I get to sprite mazing. I might not even need to do this.

I'll download your source code for Alter Ego and see what I can learn from it.

Thanks!

by on (#82044)
There's some info on the CC65 wiki: http://wiki.cc65.org/doku.php?id=cc65:p ... onventions

by on (#84095)
New version: http://kkfos.aspekt.fi/downloads/knes-0.2.zip

- Fixed to work with latest version of CC65, also included Win32 build of that specific version in the package
- Converted library subroutines to 6502 assembly
- OAM, nametables, CHR-RAM, etc are cleared in the init routine
- Updated demo project etc to use "THE" Makefile
- Added a demo of using MUSE (a music/sound library) from a C project
- Added an (almost) empty project template example
- Other small changes