VBCC Optimizing C-compiler now supports NES

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

User avatar
Lazycow
Posts: 105
Joined: Tue Jun 11, 2013 1:04 pm
Location: Germany
Contact:

Re: VBCC Optimizing C-compiler now supports NES

Post by Lazycow »

Banshaku wrote: Sat Jul 04, 2020 9:00 pm but I gave up about that for nes and adapt the C to make it faster (almost no parameters for functions and use variables in zero page for them instead).
Ha, I know this procedure from the cc65 based Wolfling game where I had to write subroutines in assembler to make it fast enough. By the way, vbcc6502 supports passing arguments over the zero page pseudo-registers r0, r1, r2, r3, etc. to assembler subroutines.
User avatar
Memblers
Site Admin
Posts: 4044
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Re: VBCC Optimizing C-compiler now supports NES

Post by Memblers »

This is some really nice work. Reading through the documentation, it sounds like there is quite a lot of optimization before it even gets to the 6502 backend. Whatever it's doing, it's showing some impressive results.

Lazycow, can you show us a code size comparison of the bubbles demo?

My current NES C programs are still too simple to benefit, but I do have some existing and planned C code that I'll eventually begin porting to NES. I could try vbcc with that.

For SNES I've been looking into trying libSFX with cc65. I'd be fine with a C compiler outputting 6502, but IIRC (it's been a while) some of the PPU registers expect a 16-bit write. If that's true, then some 65816 support is needed in the assembler, at least.

Notes for anyone who hasn't checked it out yet (do so):
-ANSI C compiler, also supports float type (I think cc65 does not)
-the lazynes demos are pretty cool and interesting
-there are several demos showing UNROM bankswitching
-should be fairly easy to port from neslib to lazynes, the PPU and sprite data format is compatible
vbc
Posts: 72
Joined: Sun Jun 21, 2020 5:03 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc »

Banshaku wrote: Fri Jul 03, 2020 10:56 pm It's interesting to see a new C compiler that can be used for the nes but how much stable it is compared to cc65 and how easy would it be to migrate to it?

Sometime cc65 has it own share of issues but you get used to it but migrating a new one, compared to just start from scratch, is sometime not an easy task with the asm code in the back so it would be good to know what is the current status for nes, is porting the code is possible or for now it should be use for experimental only.
vbcc should be pretty stable for the 6502. While the 6502 backend is rather new, the compiler has been in widespread use for many years. The 6502 backend passes my test suite without unexpected fails. Of course there will still be bugs, but I would definitely consider its status production quality rather than experimental.

Whether it is difficult and/or useful to port existing code usually depends on the code in question. C code should not be much of a problem. Assembly interfaces will need some adaptations.
vbc
Posts: 72
Joined: Sun Jun 21, 2020 5:03 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc »

Lazycow wrote: Sat Jul 04, 2020 1:27 pm - You have to switch to vasm. (correct me if I'm wrong) At least, I used vasm. The assembler code itself is the same of course, but the vasm directives are different. Copy & paste, copy & paste...
If you want to "cleanly" link assembly code, then it has to be in a file format that is supported by vlink. It does support a number of object formats like ELF and a.out, but I believe cc65 uses a proprietary format that is not currently supported.

vasm can use different syntax modules. If there is demand, it might be possible to create a vasm syntax module that can parse code written for the cc65 assembler. I would need to have a closer look to check if that is feasible (I am not familiar with that assembler).

If the assembly code is located at fixed addresses, it should be possible to link a binary file and set the symbols in the linker script.
Lazycow wrote: Sat Jul 04, 2020 1:27 pm - C interfaces might have to be modified. vbcc6502 supports register A and A/X for 1 parameter functions like cc65, but stack parameters are not compatible.
Yes. I did think about adding a compatibility mode for vbcc, but the cc65 calling conventions just seemed too strange and inefficient.
User avatar
Banshaku
Posts: 2417
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

Re: VBCC Optimizing C-compiler now supports NES

Post by Banshaku »

@vbc

Thank you for the information. It is quite possible that cc65 is just some weird non-standard C compiler (it doesn't much for 89/99) and create non efficient code, it just that it's the one people are used since it is the better of the existing ones, assembler to some degree included (that part is up to discussion but once you know how to configure segments with it, it was better than other case).

The only reason to port an existing project would be for performance since for game, it does matter. What I would like to know (I didn't have time to read the doc yet and hopefully will browse it once I find some time between task), is it possible to "bank switch" memory in C? I don't know how what is the name for it so this is the only way I can explain it. Here's an example:

One part of the game, done in C (stage 1) all files will uses a specific part of RAM defined as "playing_ram" ($0400~$0500), the intro of the game, will use the same range but defined with a different name (let's say at intro_ram at $0400~$0500), that way, since both code are not executed at the same time, they are "sharing" the same area of ram while running. As long you init properly at the beginning, it shouldn't be a problem.

If you don't do that with cc65, then the more code you add, the more ram you use if you don't use global and share them between parts, which gets quite messy. This way, by creating "range" and defining which file use which range, you share the same part of ram since that ram can be reset between state.

I'm all for a new C compiler that is more efficient since writing some of the basic logic is C is a lot faster than asm but I just need to learn more about it first ;)

edit:

And as regarding porting neslib code to the current lib, I'm using all custom code so that wouldn't be possible so it means to convert all asm code to the new ones, make sure that parameters (where there are any) are ported properly, checking it you can do "trampoline" code to switch bank on calling C function and go back to original banks etc. There is a lot of thing to test. Doable but quite a big tasks since those are nes specifics and need to be adapted.

edit2:

Still, you got me interested now so I may try to port one project to it and see how it goes. I redid some project code in 2018 in C to see how the performance would be and now feel like it may be worth trying again, if it can help programming more in C than asm. That's a huge saving in time and always didn't like how the C in cc65 was "unusual".

edit3:

If it can create dependencies for make (I guess it should) and can generate a dbg file like cc65 so it can be imported inside Mesen then that's would be great. I really need to read the doc now (laugh).
vbc
Posts: 72
Joined: Sun Jun 21, 2020 5:03 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc »

Banshaku wrote: Mon Jul 06, 2020 5:23 pm The only reason to port an existing project would be for performance since for game, it does matter. What I would like to know (I didn't have time to read the doc yet and hopefully will browse it once I find some time between task), is it possible to "bank switch" memory in C? I don't know how what is the name for it so this is the only way I can explain it. Here's an example:
For "classical" banking, i.e. where you have several memory areas that are live at the same time, but can not be visible in the address space at the same time, vbcc supports automated bank switching. The banking demos in the sample directory show some examples for the unrom configuration. With suitable library support, this can support up to 16MB of RAM/ROM. However, if I understand you correctly, for your use case you can use a simpler approach.
Banshaku wrote: Mon Jul 06, 2020 5:23 pm One part of the game, done in C (stage 1) all files will uses a specific part of RAM defined as "playing_ram" ($0400~$0500), the intro of the game, will use the same range but defined with a different name (let's say at intro_ram at $0400~$0500), that way, since both code are not executed at the same time, they are "sharing" the same area of ram while running. As long you init properly at the beginning, it shouldn't be a problem.
If you just want to put groups of data in the same overlaying RAM areas, you can use the __section attribute or #pragma section to put them into special sections, e.g.:

Code: Select all

#pragma section bss1
char a[100];
#pragma section bss2
char b[100];
#pragma section default
Then you can map those in the linker script, e.g. by adding those lines:

Code: Select all

MEMORY
{
  ...
  ram1:    org=0x0400, len=0x0100
  ram2:    org=0x0400, len=0x0100
}
...
SECTIONS
{
  ...
  bss1 (NOLOAD): {*(bss1)} >ram1
  bss2 (NOLOAD): {*(bss2)} >ram2
  ...
}
Instead of using the #pragma to map the variables, it should also be possible to do it based on the file name by using {file1.o(bss)} instead of {*(bss1)}.

The solution above assumes that the data has no initial values. If you want to use overlaid initialized data, you have to slightly modify this to e.g.:

Code: Select all

SECTIONS
{
  ...
  data1 : {*(data1)} >ram1 AT>ROM
  data2 : {*(data2)} >ram2 AT>ROM
  ...
}
  __DATA1_INIT = LOADADDR(data1);
  __DATA1_INIT = LOADADDR(data2);
Before using the variables, you have to initialize them by copying the init values from ROM to RAM, e.g.:

Code: Select all

main()
{
  memcpy((void*)0x400,&_DATA1_INIT,0x100);
  do_part1();
  memcpy((void*)0x400,&_DATA2_INIT,0x100);
  do_part2();
}  
If it can create dependencies for make
Option -deps
and can generate a dbg file like cc65 so it can be imported inside Mesen then that's would be great.
What debug format ist used by Mesen? Is there a specification available?
User avatar
Banshaku
Posts: 2417
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

Re: VBCC Optimizing C-compiler now supports NES

Post by Banshaku »

I think most of it have been answered, just one thing that I want to confirm:
vbc wrote: Tue Jul 07, 2020 10:01 am If you just want to put groups of data in the same overlaying RAM areas, you can use the __section attribute or #pragma section to put them into special sections, e.g.:
Putting a pragma on a specific variable can be useful when you want to use zero page but for every variable for a specific BSS can be time consuming. I see that you can define that in the linker but if you have multiple files that can use that, that seems quite a lot of managements to be done in that file (maybe I'm just too used to cc65 way). In cc65, you can define file scope prgrama for data/bss/ this way:

Code: Select all

#pragma code-name ("INTRO1_CODE")
#pragma rodata-name ("INTRO1_DATA")
#pragma bss-name ("BSS_INTRO")
or you can set a range of variable with this type of pragma (not sure if this is something common in C)

Code: Select all

#pragma bss-name (push, "BSS_PLAYING")

unsigned char m_idx;

extern entity_t m_entityList[10];
extern entity_t* g_current_entity;

#pragma bss-name (pop)
This way, it first "push" the segment to use BBS_INTRO, then that group of variable will be inserted inside BBS_INTRO without doing a file scope or individual settings. Then it "pop" the segment to go back to the one configured.

I will check the doc to see if there is other ways to scope variables, just didn't have time yet to go into details about that.

For deps, understood.
What debug format ist used by Mesen? Is there a specification available?
From what I understand, this is not specific to mesen but cc65 but I cannot say if it's a unique format by cc65 or some other specification they are following (I need to check their doc about it). This file contains a lot of information about the names of the current symbols and allows to debug asm with the comments and symbols you wrote and C to some degree. This is quite useful for nes debugging compared to raw addresses only. Maybe this is something that can be generated with a python script from existing vbcc output files once I understand how it works.

If I find a specification, I will share the link here.

Thank you again for the information, I really appreciate it.
User avatar
NovaSquirrel
Posts: 483
Joined: Fri Feb 27, 2009 2:35 pm
Location: Fort Wayne, Indiana
Contact:

Re: VBCC Optimizing C-compiler now supports NES

Post by NovaSquirrel »

vbc wrote: Tue Jul 07, 2020 10:01 am What debug format ist used by Mesen? Is there a specification available?
It supports ca65 debug information directly but it also has its own format that's described in its documentation.
User avatar
Banshaku
Posts: 2417
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

Re: VBCC Optimizing C-compiler now supports NES

Post by Banshaku »

I checked the cc65 and they have no explanation about the format so it may not be a good idea to add it unless someone wants to reverse engineer the format. I guess for emulators they provide a c++ class or something like that to import the format but I don't think it's made to generate the same format.

Maybe using the format Sour made for Mesen would be more productive since it's not related to cc65 (which is not an universal format and unfinished from what I understood) and if the need arise to add something new, I'm sure he can figure out something ;)
Sour
Posts: 891
Joined: Sun Feb 07, 2016 6:16 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by Sour »

The .mlb files aren't really a replacement for cc65/ca65's .dbg files - the .dbg files contain a lot more information which allow stuff like source level debugging, etc. The .mlb files are just meant to be labels, and nothing more.

I don't think there's an actual specification for .dbg files (and it's a fairly complex format) - Mesen just parses them using code I wrote.
vbc
Posts: 72
Joined: Sun Jun 21, 2020 5:03 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc »

Banshaku wrote: Tue Jul 07, 2020 6:39 pm Putting a pragma on a specific variable can be useful when you want to use zero page but for every variable for a specific BSS can be time consuming.
You do not have to put the #pragma on every variable. It affects all variables until #pragma default.
I see that you can define that in the linker but if you have multiple files that can use that, that seems quite a lot of managements to be done in that file (maybe I'm just too used to cc65 way).
I do not quite understand the problem. You basically have three options:
- use the __section attribute to put specific variables into sections
- use #pragma section to put a range of variables into a section
- use the linker file to put all variables of specified files into a section

I really cannot think how it could be much more comfortable. ;-)
vbc
Posts: 72
Joined: Sun Jun 21, 2020 5:03 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc »

Sour wrote: Tue Jul 07, 2020 10:23 pm The .mlb files aren't really a replacement for cc65/ca65's .dbg files - the .dbg files contain a lot more information which allow stuff like source level debugging, etc. The .mlb files are just meant to be labels, and nothing more.

I don't think there's an actual specification for .dbg files (and it's a fairly complex format) - Mesen just parses them using code I wrote.
Would you be interested in agreeing on and implementing a reasonably well-defined format for debug information?

I can easily create DWARF2 debug information, but that is probably overkill here. If you can tell what kind of debug information you do support, maybe we can come up with a format that is easy for me to generate and easy for you to read.

For example:

- You do support source line information, I understand?
- Do you support variables with types?
- Do you support register and/or (software)stackpointer-relative-variables?
- Do you support multiple live-ranges (e.g. variable is at address x if PC is between a..b and at y if PC is between c..d)?
- How do you handle banked memory?
Sour
Posts: 891
Joined: Sun Feb 07, 2016 6:16 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by Sour »

In general, Mesen's labels have:
-Bankswitching support - labels are defined as offsets from the first byte of a given type of memory, rather than a memory address. So basically the labels are defined based on the byte offsets in the ROM (same logic for save ram or work ram, etc.)
-Don't support types, but support a length (so you can define a label as starting at $880 and ending at $890, for example, and the debugger will display these as labelName+1, labelName+4, etc.)

As far as CA65's .dbg files goes, it adds:
-Source file mappings (.dbg files essentially give a mapping of each byte in the .nes file to a line number in a source file)
-Mostly complete code/data separation, allowing for the entire code to be disassembled ahead of time, even outside of source code debugging (the .dbg files contain enough information to know what is code and what's data in the rom, though some guesswork is involved)
-In the source code view only, it supports label scope to some extent - so if an identical local label is defined in multiple files, etc. it can still figure out which label is being referred to (for tooltips mostly), this is based on the scope information in the .dbg file. Most of the debugger/tools have no concept of scope at the moment (this is something that came up recently in another thread, too), but this might be added eventually (though I can't promise this)

It has no concept of register or stackpointer-relative-variables, etc. The tools have been mostly written to work with assembly, not C (although cc65 is technically supported, it's not amazing by any means), so this hasn't generally been needed, but I can see how that would be fairly important for C.

I'd like to add support for this compiler eventually (and/or talk about a debug information format), but at the moment I kind of have my hands tied with other stuff at the moment, so it might unfortunately be a while until I can find the time for it.
User avatar
Banshaku
Posts: 2417
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

Re: VBCC Optimizing C-compiler now supports NES

Post by Banshaku »

vbc wrote: Wed Jul 08, 2020 1:58 am You do not have to put the #pragma on every variable. It affects all variables until #pragma default.
In that case it's the same idea as push/pop on cc65, which is fine. I need to find in the doc where all information about #pragam is defined. At first I searched pragma in the PDF but it didn't find anything. After manually opening a section, now some pragma were found so there seems to be an issue with my pdf reader. Will use something else and check again.
vbc wrote: Wed Jul 08, 2020 1:58 am I do not quite understand the problem. You basically have three options:
- use the __section attribute to put specific variables into sections
- use #pragma section to put a range of variables into a section
- use the linker file to put all variables of specified files into a section

I really cannot think how it could be much more comfortable. ;-)
I guess the questions comes from the fact that I don't know yet how it works ;) For variable, no problem, now I know how it works with the linker file with one pragma only. What I'm trying to check is how to say that the content of file x, either code or RO data, are in specific banks or even different ones at file level, not linker file level (it's possible to specify 2 different banks for code and data in cc65). In cc65, you can define at the top of the file each segment is at specific range (code is in X, RO data in Y) but I'm not sure yet how it works in that case, thus the need to find the info in the doc.

I guess my needs are based on what I'm used at the moment.

edit:

I checked the sample and I see that banks are set but with numbers. Is it possible to name those banks?

And for the linker file, is there a doc that explain how it work? I don't know that format so I'm not sure on what it is based.
vbc
Posts: 72
Joined: Sun Jun 21, 2020 5:03 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc »

Sour wrote: Wed Jul 08, 2020 4:33 pm I'd like to add support for this compiler eventually (and/or talk about a debug information format), but at the moment I kind of have my hands tied with other stuff at the moment, so it might unfortunately be a while until I can find the time for it.
That's fine. Just contact me when you have time and we can figure something out.
Post Reply