How do I compile an example c file to a .nes file using cc65 in the linux command line?
Which NES I/O library is the .c file designed to use? Shiru's neslib? The stdio console provided by cc65?
Shiru's neslib. I have a folder in the cc65 directory with shiru's examples in it. I was trying to compile example1.c for nes.
There is a _compile.bat file in the folder bit I don't know what the commands are to compile in a linux environment.
I tried:
cl65 -t nes example1.c
and got:
bash: cl65: command not found
There's a makefile here.
https://github.com/jmk/cc65-nes-examples?files=1Looks like something like
cc65 -Oi example1.c --add-source
ca65 crt0.s
ca65 example1.s
ld65 -C nes.cfg -o example1.nes crt0.o example1.o runtime.lib
but if you are using a different version of cc65 than Shiru used when he made the runtime.lib, it will error. I think you can delete that from the line, I'm away from my computer at the moment, can't remember.
By the way, I'm 99% sure that "-t nes" does nothing useful.
I get:
bash: cc65: command not found
when I try the first line.
I don't remember how to set paths on a linux machine. You will have to Google it.
dougeff wrote:
By the way, I'm 99% sure that "-t nes" does nothing useful.
(wild tangent) Having now looked, apparently it's equivalent to
-D__NES__=1
I made some great progress.
cc65 -Oi example1.c --add-source
ca65 crt0.s
ca65 example1.s
all worked after I set paths, but I got the error:
Error: nes.cfg(82): Attribute expected, got '__STACKSIZE__'
when I ran:
ld65 -C nes.cfg -o example1.nes crt0.o example1.o runtime.lib
I
That's because Shiru's examples were made with a six years old cc65. They aren't compatible with the latest version, but with the 2.13 old one.
Is there a fix to get it to compile? I'm trying to find reference example code that all compiles.
MEMORY {
# First 28 bytes of the zero page are used by NES library
ZP: start = $28, size = $d8, type = rw, define = yes;
# INES Cartridge Header
HEADER: start = $0, size = $10, file = %O ,fill = yes;
# 2 16K ROM Banks
# - startup
# - code
# - rodata
# - data (load)
PRG: start = $8000, size = $3f00, file = %O ,fill = yes, define = yes;
# NROM256
# PRG: start = $8000, size = $7f00, file = %O ,fill = yes, define = yes;
# DPCM Samples at end of the ROM
DMC: start = $7f00, size = $fa, file = %O, fill = yes;
# NROM256
# DMC: start = $ff00, size = $fa, file = %O, fill = yes;
# Hardware Vectors at end of the ROM
VECTORS: start = $7ffa, size = $6, file = %O, fill = yes;
# NROM256
# VECTORS: start = $fffa, size = $6, file = %O, fill = yes;
# 1 8K CHR Bank
CHR: start = $0000, size = $2000, file = %O, fill = yes;
# standard 2K SRAM (-zeropage)
# $0100 famitone, palette, cpu stack
# $0200 oam buffer
# $0300..$800 ca65 stack
RAM: start = $0300, size = $0500, define = yes;
# Use this definition instead if you going to use extra 8K RAM
# RAM: start = $6000, size = $2000, define = yes;
}
SEGMENTS {
HEADER: load = HEADER, type = ro;
STARTUP: load = PRG, type = ro, define = yes;
LOWCODE: load = PRG, type = ro, optional = yes;
INIT: load = PRG, type = ro, define = yes, optional = yes;
CODE: load = PRG, type = ro, define = yes;
RODATA: load = PRG, type = ro, define = yes;
DATA: load = PRG, run = RAM, type = rw, define = yes;
VECTORS: load = VECTORS, type = rw;
SAMPLES: load = DMC, type = rw;
CHARS: load = CHR, type = rw;
BSS: load = RAM, type = bss, define = yes;
HEAP: load = RAM, type = bss, optional = yes;
ZEROPAGE: load = ZP, type = zp;
}
FEATURES {
CONDES: segment = INIT,
type = constructor,
label = __CONSTRUCTOR_TABLE__,
count = __CONSTRUCTOR_COUNT__;
CONDES: segment = RODATA,
type = destructor,
label = __DESTRUCTOR_TABLE__,
count = __DESTRUCTOR_COUNT__;
CONDES: type = interruptor,
segment = RODATA,
label = __INTERRUPTOR_TABLE__,
count = __INTERRUPTOR_COUNT__;
}
SYMBOLS {
__STACKSIZE__ = $0500; # 5 pages stack
}
I had to update the file since I took the examples and tried to compile them with the latest version and had issues like you. The stack line would look like this:
Code:
__STACKSIZE__ : type = weak, value = $0500;
I included my current config file which is based on Shiru's examples. I commented out the features parts since I'm not using them.
I did make a make file that compile everything in your source folder. I may share it later if people are interested in it. For now I use a copy of the runtime to build the runtime.lib when necessary but would like to automate it late to take the files from cc65 directly.
If I can make it generic enough it could be useful for people that needs to build the runtime and build all their files in a src folder automatically.
I got a different error now that the nes.cfg file has been changed
ld65: Error: Wrong data version in `runtime.lib'
The runtime that was distributed with shiru's project is just an old version of cc65's nes.lib, with a few heavier functions removed. (
see also)
You can safely use cc65's nes.lib instead.
This sequence of events is amazingly familiar, and reminds me of the famous "babel fish puzzle" from the infocom text adventure "Hitchhiker's Guide to the Galaxy". You see you try to get the babel fish out of the dispenser, only for it to fly through a hole. If you cover the hole, then the fish bounces into a grate in the floor. If you cover the grate, the babel fish lands, then a tiny robot comes and steals it away through a panel. If you then cover the panel...etc.
Each failed step was not apparent until you fixed the previous step of the puzzle. Also, you are required by the game to go through each failed step before solving the puzzle.
Included, the basic runtime that I'm using with 2.17. The other file (runtime.lst) list which files are included. I think I'm almost using the same thing as Shiru.
Once my makefile is finished, I will release it and you will be able to build the runtime anytime you want. For now I don't like that it uses a copy in a specific folder so I want to retrieve specifics files from the cc65 folder if the version gets updated some day.
That make file will even compile your project once a few specific files are set in the lib folder (neslib/famitone) and in the src folder (your c/s files and crt files). I want to make it so that even if you use a specific neslib/famitone/crt that it still can compile some generic project. It should help for people that want to start C like project (which I'm in the same situation right now).
Will share it soon, once I find it good enough. For now, I will try to help you figure out your current issues until it is available.
Now that I switched to nes.lib, I'm getting a different error:
ld65 -C nes.cfg -o example1.nes crt0.o example1.o nes.lib
ld65: Error: Missing memory area assignment for segment `ONCE'
The only leads I have to follow are to search all the files for ONCE and try to
figure out what's going on with it.
I welcome any suggestions for finding some complete example code to start
working with and modifying
Like mentioned before, I’m working on making a sample Makefile that should make it easier to create simple c projects with the latest runtime.
I just finished an example based of Shiru’s example1.c and added some code to test famitone inside it.
It should be usable in it’s current state. Except for example.c and the cfg files, other files were not modified (crt0, neslib, famitone) since it would be a common cause of bugs if some file a refreshed with the current examples.
Librsc folder contains the latest files from cc65 (2.17) so it can be tested right away. You just call make from root folder and everything should be compiled. It is possible to compile/clean the runtime only when required.
The files may be removed at a later stage if there is some issues to include it in a personal project. It is possible to use the currently installed lbsrc on your computer by modifying the Makefile accordingly.
There is not much doc with it for now but I think the Makefile should be quite a time saver. It took me time to make it but I’m more than happy to share it if it can helps people use the latest runtime.
Since I had the same issues to make it work with the latest version, I understand how it feels when nothing compiles with no obvious reason why it failed and you don’t know yet the tool chain.
It’s a work in progress but any comments on possible issues is always appreciated.
Copied from a .cfg file that I use...notice the 'ONCE' segment.
SEGMENTS {
HEADER: load = HEADER, type = ro;
STARTUP: load = PRG, type = ro, define = yes;
LOWCODE: load = PRG, type = ro, optional = yes;
INIT: load = PRG, type = ro, define = yes, optional = yes;
CODE: load = PRG, type = ro, define = yes;
RODATA: load = PRG, type = ro, define = yes;
DATA: load = PRG, run = RAM, type = rw, define = yes;
CHARS: load = CHR, type = rw;
BSS: load = RAM, type = bss, define = yes;
HEAP: load = RAM, type = bss, optional = yes;
ZEROPAGE: load = ZP, type = zp;
ONCE: load = PRG, type = ro, define = yes;
VECTORS: load = PRG, start = $fffa, type = ro;
}
you could also write it as...
ONCE: load = PRG, type = ro, define = yes, optional = yes;
The once segment is something they added around 2.14 and is now mandatory if my memory is good. Since Shiru's example where done with 2.11, this segment was not defined in the examples.
edit:
this segment is used for constructors. Since I do not define any, this segment is not in any file and should cause no issue. It just the config file that seems to nags you if you don't define it.
edit2:
@dougeff
Since you did some C tutorials, I would like to know if you think the make file I did is useful for beginners or not. I think it is since you just create you files (.s or .c) in src and it will compile them automatically.
It compiled. Thanks everyone. I can start figuring out how to make changes now.
Quote:
Since you did some C tutorials, I would like to know if you think the make file I did is useful for beginners or not. I think it is since you just create you files (.s or .c) in src and it will compile them automatically.
I think it will be useful. Yes. I'm always thinking about changing my tutorial, so it is good for me to see other people write source code.
Maybe one day I should collaborate with you or na_th_an or cppchriscpp to write some better example code.