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

Programming NES games in C article

Programming NES games in C article
by on (#88394)
Read the article

A few simple examples
Re: Programming NES games in C article
by on (#88401)
Shiru wrote:


Shiru, very nice article! One thing I'd added to NESICIDE is the ability to see mixed-mode source during debugging. That helps -- I think, anyway -- people that want to develop in C see exactly what the C compiler generates for any particular C source line of code. Example:

Large screenshot

Also, this statement:

Shiru wrote:
The problem is that there are no comfortable debuggers for C code compiled into 6502 assembly around (yet) - ones that allow to put breakpoints on random C lines and see what the variables contain at the moment. Usually you only have an assembly level debugger in some emulators, and it is not very helpful with compiled code.


is not really true. NESICIDE can do that. I've been stepping through AlterEgo at the C level for quite a while now. Thank you for such a polished and useful example of programming for NES in C.

by on (#88405)
@Shiru :D nice chasing game

by on (#88411)
Cool game dude! Awesome article as well! Would love to read/play more. :)

by on (#88422)
cpow, I've changed that line in the text. It is great that NESICIDE has C level debugger. I can't really use it, though, because my PC is too slow to run the built emulator fullspeed (it is like 50% now), so I have to wait to the next PC upgrade.

by on (#88443)
Nice info and cleanly written.
Do you know if CC65 handles cross-bank calls well (linking symbols that have been compiled into separate banks)? This was quite a hassle with SDCC (Z80) and I ended up having to write some custom tools for it, and it still didn't work perfectly.

by on (#88444)
I don't know, haven't get to this point yet - so far all my NES projects were NROM. I only read that you can put functions and data in different banks (so they are compiled into the same addresses), but have to switch banks before accessing them by yourself.

by on (#88446)
Congratulations, that was interesting.

Something I don't understand so well :
Quote:
Due to very limited NES resources, such as CPU speed, RAM and ROM size, writting a proper, clean C code isn't very effective. To make it faster and shorter you have to do things that otherwise aren't considered acceptable. They are disable some of C advantages, making the code more low level and less structured.

There are suggestions that will make your code more effective, but certainly less readable:
....

Then you write C code that is less portable and less readable, and more low level. I don't have anything against it but doesn't this kill the purpose of using C instead of assembly ?

by on (#88448)
It is a bit low level this way, but certainly not down to the assembly level - it is still rather high level.

Random example, you have a level map that is larger than 256 bytes, lets say 32x32, and need to get a value from it using two 8-bit vars, mx and my. So, for C code:
Code:
n=map[(my<<5)+mx]

Assembly code counterpart is something like this:
Code:
 lda my
 sta ptr_l
 lda #0
 sta ptr_h
dup 5
 asl ptr_l ;<<5
 rol ptr_h
edup
 lda ptr_l
 clc
 adc mx
 sta ptr_l
 lda ptr_h
 adc #0
 sta ptr_h
 lda ptr_l
 clc
 adc #<map
 sta ptr_l
 lda ptr_h
 adc #>map
 sta ptr_h
 ldy #0
 lda [ptr_l],y

One line of the code is faster to write and easier to mantain than 20+. You probably could optimize the assembly version as it was written off the top of my head, but certainly not down to a single line.

by on (#88450)
I can see using a hybrid model of C and Assembly. Consider an RPG, where the battle logic is better expressed in C, but code the rest (NMI handler, tile display logic, sound engine, etc...) in asm.

In the past Tepples has stated that the Koei simulation games were written in C, and that is probably why they seem sluggish. I bet that we could do better.

I seriously considered making some sort of an RPG as my next nesdev project, and coding part of it in C, but I lack the time to take on such a project right now. :(

by on (#88451)
That's how it is done in my NES games - C code only works with hardware through special functions written in assembly. So NMI handler, tile updater, sound code is written in assembly, and game logic in C.

You'll run into the other problem with RPG battle logic in C - the resulting code will be huge, so the problem with bankswitching have to be solved somehow.

by on (#88452)
Shiriu, your example just convicted me the usefulness of C language !

by on (#88453)
mic_ wrote:
Do you know if CC65 handles cross-bank calls well (linking symbols that have been compiled into separate banks)? This was quite a hassle with SDCC (Z80) and I ended up having to write some custom tools for it, and it still didn't work perfectly.

Not sure what exactly you're asking here. As long as the runtime functions (pusha/popa etc) are placed in a fixed bank it should work OK. The switching itself has to be done manually of course.

by on (#88460)
mic_ wrote:
Nice info and cleanly written.
Do you know if CC65 handles cross-bank calls well (linking symbols that have been compiled into separate banks)?

It doesn't happen automagically, but depending on the calling convention used, you may be able to write a bunch of stubs that make cross-bank calls using a trampoline in the fixed bank.

by on (#88464)
Quote:
Quote:
Do you know if CC65 handles cross-bank calls well
Not sure what exactly you're asking here.


Let's say you split your code/data into separate banks which are compiled and linked separately (to avoid having duplicates of the same stuff for different combinations of banks) and then combined into a .nes file.

So e.g.

bank0.c -> bank0.obj -> bank0.bin
bank1.c -> bank1.obj -> bank1.bin
...
header + bank0.bin + bank1.bin + ... -> game.nes

If bank0 wants to call a function in bank1, can you tell CC65 to resolve the address of that function without actually putting a copy of the function in bank0 as well? Using hardcoded addresses is a PITA, and using a proxy function at a fixed address to delegate calls isn't really that nice either IMO.

With SDCC I ended up writing a tool that parsed the .SYM files generated by the linker and it would output a header file with named function pointers for any given bank that other banks could use. It didn't work when there were cross-dependencies (bank X and bank Y both wanted to call eachother), so in some instances I still had to use hardcoded addresses.

by on (#88466)
mic_ wrote:
Let's say you split your code/data into separate banks which are compiled and linked separately (to avoid having duplicates of the same stuff for different combinations of banks) and then combined into a .nes file.

In this case (when each source file is compiled+linked separately -> bin) it's not possible/easy. You should compile all the source files to objects, then link those together in a single step for it to be able to resolve everything. If you need duplicate data/code in several banks I would use macros.

by on (#88594)
Besides the article, I also wrote a few very simple examples of NES programming in C. They are prebuilt, so you may check them out without compiling, the source code is example1-4.c.

Low level library was updated for these (minor fixes), and Chase code was updated as well.

by on (#89047)
This is the input from the dead-end users perspective:

The example source gave me more practical knowledge than the article. The comments are enough but with a little more detail could be considered a tutorial in itself. Also, it's easy to make highly concatenated (and obfuscated) lines of code in C. To make a tutorial-by-commented-code some instructions could be broken down for readability.

I guess what I'm saying is that the example source is great and with a little more effort could be a tutorial in itself. :)

by on (#89048)
slobu wrote:
To make a tutorial-by-commented-code some instructions could be broken down for readability.


I think what you're looking for in this statement is interleaved C/assembly? See the screenshot I posted on the first page of this thread.

If you want to know what assembly is generated for any C statement, no matter how obfuscated the C statement is, mixed-mode debugging is the way to go.

by on (#89050)
cpow wrote:
See the screenshot I posted on the first page of this thread

cpow, that mixed-mode debugging is very cool. nice work!

by on (#89134)
Hi

I am totally new to NES development (started looking into it last week), and this is my first post here. Your article and c library is great. I had my own game up and running in a couple of hours!!! Thank you for this great tutorial!

The code is quite fast, I am doing quite a lot of stuff without slowdown.

Now, if only I had any musical and/or pixel art talent... :D

I will post my game here when it's done.

/Nioreh

by on (#89150)
You can find a musician rather easily, there are many musicians who use FamiTracker and would like to make music for a game, even for a freeware one. You can try FamiTracker forums.

Graphics is a more difficult thing, because there aren't too many pixel artists who are able to make good NES graphics and are not busy with pro projects yet (iPhone games etc). Also, there are not many people who are familiar with NES graphics limitations. Anyway, you can try PixelJoint forums.

by on (#89163)
Shiru, reading this article (and some of your source code) has been very inspiring! Thanks for writing and sharing it.

by on (#89224)
Shiru, I tried to download your famitone exporter for FamiTracker, but it gives me a 404. :( Where can I find it?

I decided to try my best at both graphics and audio myself, and I think I am doing ok :)

by on (#89231)
Nioreh wrote:
Shiru, I tried to download your famitone exporter for FamiTracker, but it gives me a 404. :( Where can I find it?

I decided to try my best at both graphics and audio myself, and I think I am doing ok :)


*aham*
http://famitracker.shoodot.net/downloads.php

by on (#89233)
Sorry, my FTP is down by some reason for two days already. FamiTracker page links to my website, there is no separate download.

Here is temporary link for FamiTone.

by on (#89257)
Shiru wrote:
Sorry, my FTP is down by some reason for two days already. FamiTracker page links to my website, there is no separate download.

Here is temporary link for FamiTone.


Thanks!

Maybe this is a bit off topic, but I can't get my music files to play correctly with famitone. When I convert it from the text export to .s I get a bunch of these:

"Warning! Note out of supported range, frame 0 row 00 channel 1"

Even if I have nothing on frame 0 row 0 (if channel 1 means square wave 1?).

When I load the music up in my game it is suuuuper slow. Like 1/20 speed or slower. If I use the music from the sample game everything is fine (Fine all the way, export - convert - play).

by on (#89272)
I can't guess what is wrong or fix anything without seeing the exported txt file at least.

by on (#89325)
Shiru wrote:
I can't guess what is wrong or fix anything without seeing the exported txt file at least.


I'm sorry. It was me being stupid :) (Note A-0 on square wave 2 was the problem).

I think I have found a bug in your library, though. Using pad_poll causes the game to crash when pressing a button at the same time as a direction on the d-pad. (or if pressing both a and b simultaneously)

Edit: I am using it kind of like this:

Code:
j=pad_poll(0);

if(j&PAD_LEFT){
      --px;
   }
else if(j&PAD_RIGHT){
      ++px;
   }



Edit 2: This is also happening on your example4.nes if you test it.

by on (#89333)
Sorry, I introduced a bug during the latest library update.

My FTP is still down. Here is temporary link to the fixed version (crt0.s and neslib.s are changed), and Chase is updated too (had the bug as well).

by on (#89344)
Thanks Shiru, but I think this version introduced another bug. Now I have to hold the A-button to get any other button to register.

Bug appears on nestopia and real hardware. Not in FCEUX.

by on (#89346)
Fixed, temporary files are updated.

by on (#89347)
Wow, that was fast. Thanks!

by on (#91392)
Shiru, do you have the source code anywhere for the runtime.lib code?

Namely, I am interested in seeing what popa and popax do.

I noticed when looking at the code for some of the neslib.s (I was looking at oam_spr) routines that there are lots of calls to "jsr popa" because that call takes 4 arguments.

Typically jsr can be a bit heavy (6 cycles for JSR plus another 6 for its RTS) and I wanted to see if any of the routines could be optimized.

Al

by on (#91403)
It is in the CC65 sources, you can download them, there are many functions. I quote these two here:

Code:
;
; Ullrich von Bassewitz, 25.10.2000
;
; CC65 runtime: Pop a from stack
;

          .export        popa
   .importzp   sp

        .macpack        cpu

.proc   popa

.if (.cpu .bitand ::CPU_ISET_65SC02)
   lda   (sp)
.else
   ldy    #0              ; (2)
    lda   (sp),y      ; (7) Read byte
.endif
         inc   sp              ; (12)
          beq   @L1             ; (14)
   rts                     ; (20)

@L1:   inc   sp+1
   rts

.endproc


Code:
;
; Ullrich von Bassewitz, 25.10.2000
;
; CC65 runtime: Increment the stackpointer by 2. For performance reasons,
;       this modules does also contain the popax function.

          .export      popax, incsp2
   .importzp   sp

        .macpack        cpu

; Pop a/x from stack. This function will run directly into incsp2

.proc   popax

   ldy     #1
      lda   (sp),y         ; get hi byte
          tax                 ; into x
.if (.cpu .bitand ::CPU_ISET_65SC02)
   lda   (sp)      ; get lo byte
.else
      dey
      lda   (sp),y      ; get lo byte
.endif

.endproc



.proc   incsp2

        inc     sp              ; 5
        beq     @L1             ; 2
        inc     sp              ; 5
        beq     @L2             ; 2
        rts

@L1:    inc     sp              ; 5
@L2:    inc     sp+1            ; 5
        rts

.endproc

by on (#92292)
Thanks for the great article, however I've got some problems with linking:
Code:
$ ld65 --version
ld65 V2.13.9 - (C) Copyright 1998-2009, Ullrich von Bassewitz

$ ld65 -o main.nes crt0.o example1.o runtime.lib -C nes.cfg
ld65: Error: Wrong data version in `runtime.lib


If I'm linking without runtime.lib I get:
"ld65: Error: nes.cfg(82): Attribute expected"
82 is the line with "__STACKSIZE__ = $0500; # 5 pages stack"

I've never developed on the NES platform (or used the cc65 binutils) before, also I'm trying to build the examples on Ubuntu.

by on (#92293)
I have ld65 2.13.2. Perharps you have some newer or WIP version of CC65? Where to get Windows build of this version?

Also, order of ld65 parameters could be important.

by on (#92299)
Version 2.13.3 is uploaded to the FTP site. Here's the changelog summary from 2.13.2 to 2.13.3 from the 2.13.3 release announcement.

cc65:
  • Fixed some macro issues.
  • Static const local data goes into RODATA, not DATA.
  • Fix problem when converting function to void pointer.
  • Fix register info for several runtime functions. Result was invalid code.
  • Fix an error in the runtime division routine.
  • Fix internal error caused by error recovery (or lack of).
  • Fix invalid handling of signed int types in some cases.
  • Fix and improve the code for compares.
  • Disallow __asm__ on global level.
  • Fix problem with access to structs returned by functions.
  • Fix an internal error in the code generator.
ca65:
  • Fix error handling in .LEFT.
  • Fix problem with .REPEAT.
  • Fix problem with alignments >= 256 bytes.
  • Fix some macro issues.
libraries:
  • Fixed problems with 80 column mode (C128 library).
  • Remove final jump to RESTOR for all CBM platforms (cc65 libraries).
  • Merge back Olivers C interrupt handling code (cc65 libraries).
  • The LINE function mistakenly enabled the BASIC ROM (TGI driver for C64).
  • Fix some issues with conio scrolling (C128 library).
  • Add missing export for CBM510 platform (cbm510 library).
  • Merge back POSIX directory routines for the Atari (atari library).
da65:
  • Fix smbx and rmbx instructions.
general:
  • Fixed/improved several error messages (all tools).
  • Several documentation changes.
  • Several documentation fixes and improvements.

by on (#92302)
2.13.3 also works for me, no changes were needed.

by on (#92330)
I got it from a repo at http://www.trikaliotis.net/debian... but I guess building it from source would be a better idea.
Re: Programming NES games in C article
by on (#100993)
Shiru, I was wondering what you ended up putting in your runtime.lib.

Is it just runtime/ plus common/zerobss.s ?
Re: Programming NES games in C article
by on (#101017)
It is standart cc65 runtime, recomplied by me. Nothing is added there, as far as I remember - none of my code for sure. I don't really remember why I did recompile it. I think I used nes.lib initially that did contain the runtime, but a ton of unneeded stuff as well, so I replaced it with the runtime only, that does not have anything platform-specific (600 to 100K in size).
Re: Programming NES games in C article
by on (#101019)
I've been looking over it, compiling my own version. I had been using yours, but I wanted to get a better idea of what's in there.

There is basically nothing useful in the nes/ lib source, unless you want to make a text only program maybe, and I think it's a good idea to replace crt0. Luckily all the runtime/ stuff is modularized, so stuff you don't used is not linked in anyway.

Apparently there's a few things I need from common/ so far zerobss.s and copydata.s were needed. Probably I will need to add more as I go along and I get link errors, but I think most of common/ I want to leave out. I'm keeping a list as I go. I'll release source and information once I've finished my current project, so anyone who's interested might learn from it.
Re: Programming NES games in C article
by on (#101021)
Here are the runtime sources that I used to compile the runtime.lib.
Re: Programming NES games in C article
by on (#101024)
Ah, that looks exactly like runtime/ + common/zerobss.s like I suspected. That answers my earlier question.
Re: Programming NES games in C article
by on (#101025)
I guess it was the same for me, I probably was just adding anything that the linker was complaining about.
Re: Programming NES games in C article
by on (#114055)
Hi, new here :) I'm impatient so I'm posting my urgent question first, will figure out where to post my introduction in a minute...

Shiru, I'm trying to use your library with Nintendulator DX v34 which requires a newer version of the debug files, so I'm trying to compile a new runtime.lib with the version of CC65 included with NDX.

When I run make with the source files you posted earlier in the thread, I get this:

Code:
c:\mingw\bin\make
../bin/ar65 a runtime.lib *.o
ar65.exe: Warning: Library `runtime.lib' not found - will be created
ar65.exe: Error: Could not open `*.o': No such file or directory
Makefile:230: recipe for target 'neslib' failed
make: *** [neslib] Error 255


I know next to nothing about GNU. Can you help out a brother?
Re: Programming NES games in C article
by on (#114066)
I don't know much about GNU either. What I did is this: first remove the 'neslib: $(AR) a runtime.lib *.o' lines from the makefile and compile. It'll produce many object files. Then put it back and compile again. It'll create the runtime.lib.
Re: Programming NES games in C article
by on (#114071)
Thanks so much man - would have never figured that out myself. I'm posting my new runtime.lib file, which I tested and it totally worked!
Re: Programming NES games in C article
by on (#114099)
I'm familiar with makefiles. Can someone upload the entire makefile so I can look at it and/or give advice on the issue?
Re: Programming NES games in C article
by on (#114102)
The makefile is included into this archive.
Re: Programming NES games in C article
by on (#114105)
Thanks.

The Makefile looks like it's missing dependencies for the neslib target. I would suggest:

Code:
neslib: $(OBJS)
   $(AR) a runtime.lib $(OBJS)


You can replace the second $(OBJS) with *.o if you want, but that may or may not be a wise idea. What this will do is make it so that any time someone does make neslib, it will build the relevant .o files (referenced by the OBJS variable) first (if they don't exist).

An example of a working dependency list would be like this:

Code:
OBJS=   main.o boards.o output.o chip_w83792d.o chip_w83793g.o chip_x6dva.o

all: bsdhwmon

bsdhwmon: ${OBJS}
        ${CC} ${CFLAGS} -o ${.TARGET} ${.ALLSRC}

${OBJS}: global.h
        ${CC} ${CFLAGS} -c ${.PREFIX}.c


In English:

bsdhwmon (the final executable) is dependent upon the .o files mentioned in OBJS. The OBJS themselves are dependent upon global.h (i.e. in case I update global.h all the .o files should be recompiled), and to recompile those .o files, cc $CFLAGS -c {objectname_minus_the_.o_part}.c will be run. The final executable build (linking) is done via cc $CFLAGS -o bsdhwmon {all the .o files}

In BSD make, $.ALLSRC is the same as $>, and $.TARGET is the same as $@. Not sure if GNU make has those alternate names as well, but I find them to be much easier to read.

Example run:

Code:
$ make
cc -O2 -pipe -fno-omit-frame-pointer -march=core2 -Werror -Wall -Wformat-security -fno-inline -c main.c
cc -O2 -pipe -fno-omit-frame-pointer -march=core2 -Werror -Wall -Wformat-security -fno-inline -c boards.c
cc -O2 -pipe -fno-omit-frame-pointer -march=core2 -Werror -Wall -Wformat-security -fno-inline -c output.c
cc -O2 -pipe -fno-omit-frame-pointer -march=core2 -Werror -Wall -Wformat-security -fno-inline -c chip_w83792d.c
cc -O2 -pipe -fno-omit-frame-pointer -march=core2 -Werror -Wall -Wformat-security -fno-inline -c chip_w83793g.c
cc -O2 -pipe -fno-omit-frame-pointer -march=core2 -Werror -Wall -Wformat-security -fno-inline -c chip_x6dva.c
cc -O2 -pipe -fno-omit-frame-pointer -march=core2 -Werror -Wall -Wformat-security -fno-inline -o bsdhwmon main.o boards.o output.o chip_w83792d.o chip_w83793g.o chip_x6dva.o


There are also some "magic" target names, like doing something like this:

Code:
%.o: %.c global.h
    ${CC} ${CFLAGS} -c ${.ALLSRC}


Which would make all the relevant .o files dependent upon their .c file equivalents, a well as global.h. See "Makefile.3" for an explanation. Lots of people use this methodology.

Anyway, you may also want to add runtime.lib as a dependency for some other target (possibly "all" ?), and then make a runtime.lib target which does the right thing there. Then there's no more "make neslib" necessity -- instead "make" just does it all for you -- it all depends on what you want, of course.

Make sense? Sorry if it's a bit confusing. :-)
Re: Programming NES games in C article
by on (#116260)
Hey there guys. New member here. I have been registered for a while and browsed for a while but never posted.. I've decided that while i have had some assembly experience i wanted to give this method a try.

With that being said, I am more of a Java guy so I am having some troubles getting setup. I followed the instructions posted here:
http://oliverschmidt.github.io/cc65/get ... arted.html

to get cc65 up and running and added it to my class path but I get the following error:

Code:
C:\cc65\src>compile.bat

C:\cc65\src>path=path;..\bin\

C:\cc65\src>set CC65_HOME=..\

C:\cc65\src>cc65 -Oi game.c --add-source
game.c(225): Warning: #pragma bssseg is obsolete, please use #pragma bss-name in
stead
game.c(226): Warning: #pragma dataseg is obsolete, please use #pragma data-name
instead

C:\cc65\src>ca65 crt0.s
crt0.s(29): Error: Cannot open include file `zeropage.inc': No such file or dire
ctory

C:\cc65\src>ca65 game.s
game.s(12): Error: Cannot open include file `longbranch.mac': No such file or di
rectory
game.s(4837): Error: `:' expected
game.s(4837): Error: Unexpected trailing garbage characters
game.s(4869): Error: Symbol `jcs' is already defined
game.s(4869): Error: `:' expected
game.s(4869): Error: Symbol `.size' is already defined
game.s(4869): Error: Unexpected trailing garbage characters
game.s(4888): Error: `:' expected
game.s(4888): Error: Unexpected trailing garbage characters
game.s(5239): Error: Symbol `jcs' is already defined
game.s(5239): Error: `:' expected
game.s(5239): Error: Symbol `.size' is already defined
game.s(5239): Error: Unexpected trailing garbage characters
game.s(5399): Error: `:' expected
game.s(5399): Error: Unexpected trailing garbage characters
game.s(5466): Error: Symbol `jcs' is already defined
game.s(5466): Error: `:' expected
game.s(5466): Error: Symbol `.size' is already defined
game.s(5466): Error: Unexpected trailing garbage characters
game.s(5513): Error: Symbol `jne' is already defined
game.s(5513): Error: `:' expected
game.s(5513): Error: Symbol `.size' is already defined
game.s(5513): Error: Unexpected trailing garbage characters
game.s(5518): Error: Symbol `jeq' is already defined
game.s(5518): Error: `:' expected
game.s(5518): Error: Symbol `.size' is already defined
game.s(5518): Error: Unexpected trailing garbage characters
game.s(5548): Error: Symbol `jcs' is already defined
game.s(5548): Error: `:' expected
game.s(5548): Error: Symbol `.size' is already defined
game.s(5548): Error: Unexpected trailing garbage characters
game.s(5688): Error: Symbol `jeq' is already defined
game.s(5688): Error: `:' expected
game.s(5688): Error: Symbol `.size' is already defined
game.s(5688): Error: Unexpected trailing garbage characters
game.s(5699): Error: Symbol `jeq' is already defined
game.s(5699): Error: `:' expected
game.s(5699): Error: Symbol `.size' is already defined
game.s(5699): Error: Unexpected trailing garbage characters
game.s(5705): Error: Symbol `jne' is already defined
game.s(5705): Error: `:' expected
game.s(5705): Error: Symbol `.size' is already defined
game.s(5705): Error: Unexpected trailing garbage characters
game.s(5912): Error: `:' expected
game.s(5912): Error: Unexpected trailing garbage characters
game.s(5930): Error: Symbol `jcc' is already defined
game.s(5930): Error: `:' expected
game.s(5930): Error: Symbol `.size' is already defined
game.s(5930): Error: Unexpected trailing garbage characters
game.s(6044): Error: Symbol `jne' is already defined
game.s(6044): Error: `:' expected
game.s(6044): Error: Symbol `.size' is already defined
game.s(6044): Error: Unexpected trailing garbage characters
game.s(6097): Error: Symbol `jne' is already defined
game.s(6097): Error: `:' expected
game.s(6097): Error: Symbol `.size' is already defined
game.s(6097): Error: Unexpected trailing garbage characters
game.s(6286): Error: Symbol `jeq' is already defined
game.s(6286): Error: `:' expected
game.s(6286): Error: Symbol `.size' is already defined
game.s(6286): Error: Unexpected trailing garbage characters
game.s(6291): Error: Symbol `jne' is already defined
game.s(6291): Error: `:' expected
game.s(6291): Error: Symbol `.size' is already defined
game.s(6291): Error: Unexpected trailing garbage characters
game.s(6371): Error: Symbol `jeq' is already defined
game.s(6371): Error: `:' expected
game.s(6371): Error: Symbol `.size' is already defined
game.s(6371): Error: Unexpected trailing garbage characters
game.s(6603): Error: Symbol `jcc' is already defined
game.s(6603): Error: `:' expected
game.s(6603): Error: Symbol `.size' is already defined
game.s(6603): Error: Unexpected trailing garbage characters
game.s(6759): Error: Symbol `jeq' is already defined
game.s(6759): Error: `:' expected
game.s(6759): Error: Symbol `.size' is already defined
game.s(6759): Error: Unexpected trailing garbage characters

C:\cc65\src>ld65 -C nes.cfg -o Chase.nes crt0.o game.o runtime.lib
ld65: Error: nes.cfg(82): Attribute expected

C:\cc65\src>pause
Press any key to continue . . .


Looks like it has something to do with the make file stuff you all were mentioning above so I wanted to get some clarification. Do I need to basically redo the steps in the cc65 installation link but before I run the make.exe for cc65 replace the makefile with the one you all provided?
Re: Programming NES games in C article
by on (#127476)
would anyone still have that runtime.zip file? I'm having a little trouble getting runtime.lib built
Re: Programming NES games in C article
by on (#127482)
The sources for runtime stuff are in the CC65 source package.
Re: Programming NES games in C article
by on (#127483)
yeah I was just looking for shiru's makefile. I already compiled ca65 from src. and i built the libs. But runtime.lib doesn't get built. I tried "make lib" and "make all"

shiru's examples don't compile with newer versions of ca65 because it complains version differs. so I wanted to build runtime.lib myself. in another thread he said he renamed runtime.lib. I think he just used certain .o's. which is why I wanted to look at his makefile. can't use "ar65 l" on runtime.lib either.

renaming nes.lib to runtime.lib might work.
Re: Programming NES games in C article
by on (#127484)
You might just try building everything in /common and /runtime and packing them into a lib. (I dunno, though, setting up a suitable runtime library collection is a bit of an advanced task. Hard to do right unless you're well versed in NES and 6502 assembly.)
Re: Programming NES games in C article
by on (#127488)
DrDementia wrote:
shiru's examples don't compile with newer versions of ca65 because it complains version differs. so I wanted to build runtime.lib myself. in another thread he said he renamed runtime.lib. I think he just used certain .o's. which is why I wanted to look at his makefile. can't use "ar65 l" on runtime.lib either.

Why don't you use the runtime.lib that sonder posted in this thread?
Re: Programming NES games in C article
by on (#127601)
thefox wrote:
Why don't you use the runtime.lib that sonder posted in this thread?


:P swear I tried that before. OK here's a little update
sonder's runtime.lib does work for me with latest version of cc65, I tried nenaming nes.lib(from CC65) to runtime.lib, that seems to work too. I can use "ar65 l" on both those, and runtime.lib seems to contain mostly math stuff, all of which seem to be in nes.lib. the nes lib contains some nes specific stuff, not sure if that will cause any conflicts.