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

timschuerewegen
Posts: 38
Joined: Wed Dec 04, 2019 10:42 am

Re: VBCC Optimizing C-compiler now supports NES

Post by timschuerewegen »

vbc wrote: Wed Aug 12, 2020 1:07 pmNo, DATA2 is defined as an array of pointers to constant char, not an array of constant pointers to char. This should work:

Code: Select all

const unsigned char *const DATA2[] =
{
	DATA1, DATA1, DATA1, DATA1
};
Doh! Thanks (and sorry). I learned something new today :)
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 »

Thanks for getting it to build, lazycow. My cat also likes this demo, haha.

I did notice another thing in lnAddSpr that could be optimized, maybe a little controversial though. The INX INX INX INX sequence could be replaced with TXA / AXS #$FC unofficial opcode (it trashes A, but the loop trashes it already). That will be 4 cycles faster per iteration. I never paid much attention to the unofficial NMOS 6502 ops, but AXS immediate ($CB) seems to be one of the most useful ones. It's sure to break something somewhere though (the Project Nested emulator comes to mind, dunno what else).

I was doing a funny experiment with vbcc last night, and ran into a bug or something I don't understand. I'm compiling a 6502 emulator (fake6502). It's set up so every emulated memory read simply returns $EA to make it NOP forever. It barely fits into memory, rodata overflows unless I combine -size with -O2 (or higher). (see edit below) It compiles, but doesn't assemble because some labels are missing.

vc +nrom256v -c99 -+ -O3 -size cpu.c fake6502.c -o cpu.nes

Code: Select all

\Users\membl\AppData\Local\Temp\vbcc068c.o: In "_callexternal":
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0xf): Reference to undefined symbol l62.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x13): Reference to undefined symbol l62.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x2f): Reference to undefined symbol l65.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x33): Reference to undefined symbol l65.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x4f): Reference to undefined symbol l62.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x53): Reference to undefined symbol l62.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x6f): Reference to undefined symbol l65.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x73): Reference to undefined symbol l65.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x8f): Reference to undefined symbol l62.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x93): Reference to undefined symbol l62.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0xaf): Reference to undefined symbol l65.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0xb3): Reference to undefined symbol l65.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0xcf): Reference to undefined symbol l62.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0xd3): Reference to undefined symbol l62.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0xef): Reference to undefined symbol l65.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0xf3): Reference to undefined symbol l65.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x10f): Reference to undefined symbol l62.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x113): Reference to undefined symbol l62.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x12f): Reference to undefined symbol l65.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x133): Reference to undefined symbol l65.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x139): Reference to undefined symbol l38.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x13b): Reference to undefined symbol l38.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x14f): Reference to undefined symbol l62.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x153): Reference to undefined symbol l62.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x16f): Reference to undefined symbol l65.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x173): Reference to undefined symbol l65.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x179): Reference to undefined symbol l38.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x17b): Reference to undefined symbol l38.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x18f): Reference to undefined symbol l62.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x193): Reference to undefined symbol l62.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x1af): Reference to undefined symbol l65.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x1b3): Reference to undefined symbol l65.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x1cf): Reference to undefined symbol l62.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x1d3): Reference to undefined symbol l62.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x1ef): Reference to undefined symbol l65.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x1f3): Reference to undefined symbol l65.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x35d): Reference to undefined symbol l459.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x38d): Reference to undefined symbol l230.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x395): Reference to undefined symbol l230.
Error 21: \Users\membl\AppData\Local\Temp\vbcc068c.o (data+0x3a5): Reference to undefined symbol l230.
vlink -b rawbin1 -Cvbcc -T%VBCC%/targets/6502-nes/nrom256v.cmd -L%VBCC%/targets/6502-nes/lib %VBCC%/targets/6502-nes/lib/startup.o "C:\Users\membl\AppData\Local\Temp\vbcc068c.o"   -o cpu.nes -lvc failed
If I build with -O2, there is a longer list of undefined symbols. -O3 and -O4 appears to be the same.

If I build with -S and look at the source, I can indeed see the references to the labels that look like this, but no label anywhere (in this copy/paste l230 is missing, surrounded by references to labels that do exist).

Code: Select all

	word	l230
	word	l206
	word	l350
	word	l507
	word	l230
	word	l206
	word	l242
	word	l507
	word	l296
	word	l206
	word	l251
	word	l350
	word	l230
edit:
I was mistaken, the version I posted does compile if I exclude the -size option. The above error only happens with -size. The resulting program crashes (invalid op in Mesen) when run though. Removed calls to reset6502() step6502(), and it's still a black screen (but no invalid op, at least). Removing fake6502.c from the build lets it work again (as in, the blue blackground is there and printf works).
Attachments
fake6502.c
(28.69 KiB) Downloaded 176 times
cpu.c
(481 Bytes) Downloaded 176 times
vbc
Posts: 72
Joined: Sun Jun 21, 2020 5:03 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc »

Memblers wrote: Thu Aug 13, 2020 4:55 pm I was doing a funny experiment with vbcc last night, and ran into a bug or something I don't understand. I'm compiling a 6502 emulator (fake6502). It's set up so every emulated memory read simply returns $EA to make it NOP forever. It barely fits into memory, rodata overflows unless I combine -size with -O2 (or higher). (see edit below) It compiles, but doesn't assemble because some labels are missing.
Thanks for the report. The code compressor apparently got confused by some static functions that are only called through function pointers. I will have a look at it. In the meantime you can probably work around it by avoiding static functions (e.g. using -Dstatic= ).

edit:
I was mistaken, the version I posted does compile if I exclude the -size option. The above error only happens with -size. The resulting program crashes (invalid op in Mesen) when run though. Removed calls to reset6502() step6502(), and it's still a black screen (but no invalid op, at least). Removing fake6502.c from the build lets it work again (as in, the blue blackground is there and printf works).
Thanks! There is a stupid typo in the startup code leading to an incorrectly initialized data segment:

Code: Select all

; copy initialized data from ROM to RAM
        lda #<__DS
        sta r0
        lda #>__DE    <= should be __DS of course!
I have attached fixed startup code and I will be updating the distribution on my page shortly.

Btw. if you declare the function pointer arrays like this

Code: Select all

static void (*const addrtable[256])() = {
...
static void (*const optable[256])() = {
then they will be placed in ROM only rather than being copied from ROM to RAM.
Attachments
startupfix.zip
(3.5 KiB) Downloaded 182 times
timschuerewegen
Posts: 38
Joined: Wed Dec 04, 2019 10:42 am

Re: VBCC Optimizing C-compiler now supports NES

Post by timschuerewegen »

Code: Select all

#include <lazynes.h>
#include <string.h>

void draw_text_1(ubyte x, ubyte y, const char *text)
{
	uword addr = lnNameTab0 + (y * 32) + x;
	lnPush(addr, strlen(text), text);
}

void draw_text_2(ubyte x, ubyte y, const char *text)
{
	lnPush(lnNameTab0 + (y * 32) + x, strlen(text), text);
}

int main()
{
	static const ubyte COLORS[] = { 2, 33 };

	lnSync(lfBlank);
	lnPush(lnBackCol, 2, COLORS);
	draw_text_1(13, 13, "TEXT 1");
	draw_text_2(13, 15, "TEXT 2");
	lnSync(0);

	return 0;
}
good:
vc +nrom256v -c99 -O1 lazyhello.c lazydata.s -llazynes -o lazyhello.nes
1.png
1.png (1.11 KiB) Viewed 12593 times
not good:
vc +nrom256v -c99 -O0 lazyhello.c lazydata.s -llazynes -o lazyhello.nes
2.png
2.png (1.09 KiB) Viewed 12593 times
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 »

vbc wrote: Fri Aug 14, 2020 8:13 am
Btw. if you declare the function pointer arrays like this

Code: Select all

static void (*const addrtable[256])() = {
...
static void (*const optable[256])() = {
then they will be placed in ROM only rather than being copied from ROM to RAM.
Thanks for the tip, changing those to const does fix it, and with that fake6502 uses less than 64 bytes of RAM. I also tested the startupfix, initializing now works, for this demo I'll leave the initialized part in because it actually sounds kind of cool (I'm outputting the emulated 6502 bus through the $4011 audio DAC).

Compiled with vbcc6502 it's running quite a bit faster than the cc65 version. This is awesome! Sometime I'll run a 6502 test ROM through it, which will exercise all that code in fake6502.c.

I posted it with some more details over here, will attach the demo here and update that post:
viewtopic.php?f=22&t=20673

Here's what I think we're hearing in the vbcc-built version:
seconds
00~05 - polling $2002?
06~06 - clearing NES RAM
07~13 - loading initialized data
13+ - emulated CPU is stuck in an infinite loop

Note this demo is was written expecting it to crash, as there are 2 emulated 6502s stepping all over eachothers RAM. Emulator must support NROM+WRAM.
Attachments
cpu2.zip
(16.65 KiB) Downloaded 181 times
vbc
Posts: 72
Joined: Sun Jun 21, 2020 5:03 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc »

timschuerewegen wrote: Fri Aug 14, 2020 1:46 pm good:
vc +nrom256v -c99 -O1 lazyhello.c lazydata.s -llazynes -o lazyhello.nes

not good:
vc +nrom256v -c99 -O0 lazyhello.c lazydata.s -llazynes -o lazyhello.nes
Who would want to use -O0? :-)

I have updated my page with a fixed version (including also the startup fix).

Thanks for the report.
yaros
Posts: 47
Joined: Tue Aug 28, 2018 8:54 am

Re: VBCC Optimizing C-compiler now supports NES

Post by yaros »

vbc wrote: Tue Aug 18, 2020 4:25 am I have updated my page with a fixed version (including also the startup fix).
Thanks for the new compiler! Which version contains latest fixes? The latest beta I got from the website, has latest updated file dated August 9th. Or should I build the latest from the provided source code?

edit:
Banshaku wrote: Fri Jul 17, 2020 6:01 pm Regarding the vice label, yes, that should be a lot easier to parse than the map file so I should look into this. I will ask Sour if there is a simple way to convert a vice file to make it compatible with mesen. Even just for the asm symbols, that would already help a lot.
Not sure if you figured it out. I wrote simple Python script to convert vicelabels to mesen labels.

edit2:
I have couple of questions.
Can I link to assembly file (without __reg(X)) or use inline assembler and preserve Register Allocation optimization? I guess not, as even std library uses __reg(X).
Who's responsible for preserving a/x/y and rN registers, caller or callee? Or compiler will see their usage and work around it?
Attachments
convertlabels.txt
(869 Bytes) Downloaded 173 times
vbc
Posts: 72
Joined: Sun Jun 21, 2020 5:03 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc »

yaros wrote: Sun Aug 23, 2020 3:48 pm Thanks for the new compiler! Which version contains latest fixes? The latest beta I got from the website, has latest updated file dated August 9th. Or should I build the latest from the provided source code?
Apparently I forgot to update the link (the text mentioned patch e, but the link still pointed to patch d). Now it correctly points to vbcc6502_3e.zip which includes the latest updates. Thanks for the hint.
Not sure if you figured it out. I wrote simple Python script to convert vicelabels to mesen labels.
Thank you!
I have couple of questions.
Can I link to assembly file (without __reg(X)) or use inline assembler and preserve Register Allocation optimization? I guess not, as even std library uses __reg(X).
Who's responsible for preserving a/x/y and rN registers, caller or callee? Or compiler will see their usage and work around it?
This is listed in the documentation under 6502 Backend=>ABI: r16..r27 are callee-save, all other are caller-save. vbcc assumes that all called functions adhere to this convention. If vbcc knows that a called function does not modify some caller-save registers, it can make use of that information - but it will not fix a function that clobbers callee-save registers.
yaros
Posts: 47
Joined: Tue Aug 28, 2018 8:54 am

Re: VBCC Optimizing C-compiler now supports NES

Post by yaros »

vbc wrote: Mon Aug 24, 2020 4:49 am
yaros wrote: Sun Aug 23, 2020 3:48 pm Not sure if you figured it out. I wrote simple Python script to convert vicelabels to mesen labels.
Thank you!
Mesen labels specifically target NES memory model, not sure if it's good idea to integrate into the your compiler. But as you can see from the script, it's very easy. You can find documentation here:
vbc wrote: Mon Aug 24, 2020 4:49 am This is listed in the documentation under 6502 Backend=>ABI: r16..r27 are callee-save, all other are caller-save. vbcc assumes that all called functions adhere to this convention. If vbcc knows that a called function does not modify some caller-save registers, it can make use of that information - but it will not fix a function that clobbers callee-save registers.
I'm sorry. I spent 3 hours yesterday reading forum and vbcc, vasm, vlink documentation. I have probably missed it...
yaros
Posts: 47
Joined: Tue Aug 28, 2018 8:54 am

Re: VBCC Optimizing C-compiler now supports NES

Post by yaros »

yaros wrote: Mon Aug 24, 2020 9:34 am
vbc wrote: Mon Aug 24, 2020 4:49 am
yaros wrote: Sun Aug 23, 2020 3:48 pm Not sure if you figured it out. I wrote simple Python script to convert vicelabels to mesen labels.
Thank you!
Mesen labels specifically target NES memory model, not sure if it's good idea to integrate into the your compiler. But as you can see from the script, it's very easy. You can find documentation here:
vbc wrote: Mon Aug 24, 2020 4:49 am This is listed in the documentation under 6502 Backend=>ABI: r16..r27 are callee-save, all other are caller-save. vbcc assumes that all called functions adhere to this convention. If vbcc knows that a called function does not modify some caller-save registers, it can make use of that information - but it will not fix a function that clobbers callee-save registers.
I'm sorry. I spent 3 hours yesterday reading forum and vbcc, vasm, vlink documentation. I have probably missed it...

edit:
If I export subroutine with r0/r1 as input parameters, will compiler know that I also clobber r2/r3?
yaros
Posts: 47
Joined: Tue Aug 28, 2018 8:54 am

Re: VBCC Optimizing C-compiler now supports NES

Post by yaros »

vbc wrote: Mon Aug 24, 2020 4:49 am
Thank you!
Mesen labels specifically target NES memory model, not sure if it's good idea to integrate into the your compiler. But as you can see from the script, it's very easy. You can find documentation here:
vbc wrote: Mon Aug 24, 2020 4:49 am This is listed in the documentation under 6502 Backend=>ABI: r16..r27 are callee-save, all other are caller-save. vbcc assumes that all called functions adhere to this convention. If vbcc knows that a called function does not modify some caller-save registers, it can make use of that information - but it will not fix a function that clobbers callee-save registers.
I'm sorry. I spent 3 hours yesterday reading forum and vbcc, vasm, vlink documentation. I have probably missed it...

edit:
If I export subroutine with r0/r1 as input parameters, will compiler know that I also clobber r2/r3?
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 »

yaros wrote: Sun Aug 23, 2020 3:48 pm
Banshaku wrote: Fri Jul 17, 2020 6:01 pm Regarding the vice label, yes, that should be a lot easier to parse than the map file so I should look into this. I will ask Sour if there is a simple way to convert a vice file to make it compatible with mesen. Even just for the asm symbols, that would already help a lot.
Not sure if you figured it out. I wrote simple Python script to convert vicelabels to mesen labels.
I was able to convert one project up to the sound driver and converting famitracker to vasm is no easy task so for now it's on hold. To get back to write asm, I converted that project back to complete asm and later I may be more up to the challenge to do it.

So for now this project is on hold until I work back on it. If I do work back and convert the driver, I will share it but it may take time.
vbc
Posts: 72
Joined: Sun Jun 21, 2020 5:03 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc »

yaros wrote: Mon Aug 24, 2020 12:52 pm If I export subroutine with r0/r1 as input parameters, will compiler know that I also clobber r2/r3?
Yes. It assumes everything apart from r16..r27 could be clobbered by a call to an external function.
yaros
Posts: 47
Joined: Tue Aug 28, 2018 8:54 am

Re: VBCC Optimizing C-compiler now supports NES

Post by yaros »

Found a bug with #pragma dontwarn. It still warns.

Code:

Code: Select all

int main()
{
    unsigned char i = 0;
    // comment
    #pragma dontwarn 208
    while(1) {
        i++;
    }
    #pragma popwarn
}
Result:

Code: Select all

PS D:\...\test_vbcc> vc +nes -O3 -c99 main.c -o test_vbcc.nes
warning 208 in function "main": suspicious loop
Edit:
I have something weird going on. Simple hello world stopped working. I got new version of VBCC downloaded and replaced, just in case, because I was playing with configurations. Instead of "Hello world" it simply shows blue screen.

Code: Select all

// build with vc +nrom256v -+ -c99 main.c -o test_vbcc2.nes
#include <stdio.h>

int main()
{
    printf("Hello World");
}
Edit2:

Looks like a bug. It doesn't print without \n. The following works.

Code: Select all

#include <stdio.h>

int main()
{
    printf("hello world\n");
}
vbc
Posts: 72
Joined: Sun Jun 21, 2020 5:03 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc »

yaros wrote: Tue Aug 25, 2020 2:27 pm Result:

Code: Select all

PS D:\...\test_vbcc> vc +nes -O3 -c99 main.c -o test_vbcc.nes
warning 208 in function "main": suspicious loop
This warning is produced by a global optimizer pass and can not be disabled locally. You can only disable it globally.
Looks like a bug. It doesn't print without \n. The following works.

Code: Select all

#include <stdio.h>

int main()
{
    printf("hello world\n");
}
stdio is line-buffered on NES. Either print a linefeed or use fflush(stdout); to make the output appear.
Post Reply