VBCC Optimizing C-compiler now supports NES

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

Post Reply
User avatar
Lazycow
Posts: 99
Joined: Tue Jun 11, 2013 1:04 pm
Contact:

VBCC Optimizing C-compiler now supports NES

Post by Lazycow » Wed Jun 24, 2020 11:35 am

I'm posting here on Volker Barthelmann's behalf, whos accound hasn't been approved, yet. (admin: hint, hint) :wink:
---8<---
Hello,

I have just released the second version of a port of the vbcc compiler to the 6502 at:
http://www.compilers.de/vbcc.html

Thanks to Matthias "Lazycow" Bock, the NES is now a supported target system, and this distribution also includes the lazyNES library with all crucial functionality to write NES games in C (see samples/lazynes).

It contains a C compiler, assembler, linker and a very rushed port of a C Library for the C64 and NES.

A few of the good things:

- compiler is under active development
- supports C99 (variable-length arrays, designated initializers etc.)
- generates optimized code (see dhrystones in sample directory)
- supports banked memory and far-pointers
- (limited) floating point support based on Steve Wozniaks code
- (pretty good) 32/64bit IEEE floating point support based on SANE
- support for writing interrupt handlers
- attributes for putting variables into zero page
- supports stack-frames > 256 bytes

More details in the included pdf.

Image

User avatar
Jarhmander
Formerly ~J-@D!~
Posts: 497
Joined: Sun Mar 12, 2006 12:36 am
Location: Rive nord de Montréal

Re: VBCC Optimizing C-compiler now supports NES

Post by Jarhmander » Thu Jun 25, 2020 4:51 am

Wait, two C compilers released less than a week apart? What's this, the year of the C compilers? That being said, that's awesome.

I know some members here would like to see some code examples, like what the equivalent of a hand coded memcpy in C looks like in assembly once compiled.
((λ (x) (x x)) (λ (x) (x x)))

User avatar
Nikku4211
Posts: 26
Joined: Sun Dec 15, 2019 1:28 pm
Location: Bronx, New York
Contact:

Re: VBCC Optimizing C-compiler now supports NES

Post by Nikku4211 » Sat Jun 27, 2020 10:57 am

Nice. Do you plan to support SNES? I know there's already PVSNESLib, but it's not really great to be honest...
I have an ASD, so empathy is not natural for me. If I hurt you, I apologise.

vbc
Posts: 3
Joined: Sun Jun 21, 2020 5:03 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc » Mon Jun 29, 2020 7:49 am

Jarhmander wrote:
Thu Jun 25, 2020 4:51 am
Wait, two C compilers released less than a week apart? What's this, the year of the C compilers? That being said, that's awesome.

I know some members here would like to see some code examples, like what the equivalent of a hand coded memcpy in C looks like in assembly once compiled.
My registration seems to work now.

Code: Select all

void memcpy(char *d,char *s,unsigned int n)
{
  while(n){*d++=*s++;n--;}
}
with vc -O3 compiles to:

Code: Select all

;vcprmin=10000                                                                  
        section text
        global  _memcpy
_memcpy:
        lda     r5
        bne     l22
        lda     r4
        beq     l9
l22:
l8:
        ldy     #0
        lda     (r2),y
        sta     (r0),y
        inc     r2
        bne     l23
        inc     r3
l23:
        inc     r0
        bne     l24
        inc     r1
l24:
        lda     r4
        bne     l25
        dec     r5
l25:
        dec     r4
        lda     r5
        bne     l8
        lda     r4
        bne     l8
l9:
        rts
cc65 -Oisr generates:

Code: Select all

.proc	_memcpy: near

.segment	"CODE"

	jsr     pushax
	jmp     L0004
L0002:	ldy     #$05
	lda     (sp),y
	tax
	dey
	lda     (sp),y
	sta     regsave
	stx     regsave+1
	clc
	adc     #$01
	bcc     L0007
	inx
L0007:	jsr     staxysp
	lda     regsave
	ldx     regsave+1
	jsr     pushax
	ldy     #$05
	lda     (sp),y
	tax
	dey
	lda     (sp),y
	sta     regsave
	stx     regsave+1
	clc
	adc     #$01
	bcc     L0009
	inx
L0009:	jsr     staxysp
	ldy     #$00
	lda     (regsave),y
	jsr     staspidx
	ldy     #$01
	lda     (sp),y
	tax
	dey
	lda     (sp),y
	sec
	sbc     #$01
	bcs     L000B
	dex
L000B:	jsr     stax0sp
L0004:	ldy     #$01
	lda     (sp),y
	dey
	ora     (sp),y
	bne     L0002
	jmp     incsp6

.endproc

User avatar
aa-dav
Posts: 54
Joined: Tue Apr 14, 2020 9:45 pm
Location: Russia

Re: VBCC Optimizing C-compiler now supports NES

Post by aa-dav » Mon Jun 29, 2020 9:44 pm

vbc wrote:
Mon Jun 29, 2020 7:49 am
...
Cool! Could you test this example please:

Code: Select all

void str_cpy(char *d,char *s)
{
  while ( *d++ = *s++ ) {};
}
Looks like your compiler analizes call tree and places parameters in global variables if possible. Is it true? But does it support recursion? If yes, what code will be generated if parameters will be in stack?

vbc
Posts: 3
Joined: Sun Jun 21, 2020 5:03 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc » Tue Jun 30, 2020 3:43 am

aa-dav wrote:
Mon Jun 29, 2020 9:44 pm
vbc wrote:
Mon Jun 29, 2020 7:49 am
...
Cool! Could you test this example please:

Code: Select all

void str_cpy(char *d,char *s)
{
  while ( *d++ = *s++ ) {};
}
vbcc does not like the post-increment in the loop condition too much and makes a copy of the pointers:

Code: Select all

;vcprmin=10000
        section text
        global  _str_cpy
_str_cpy:
        lda     r3
        sta     r7
        lda     r2
        sta     r6
        inc     r2
        bne     l20
        inc     r3
l20:
        lda     r1
        sta     r5
        lda     r0
        sta     r4
        inc     r0
        bne     l21
        inc     r1
l21:
        ldy     #0
        lda     (r6),y
        sta     (r4),y
        cmp     #0
        beq     l7
l6:
        lda     r3
        sta     r7
        lda     r2
        sta     r6
        inc     r2
        bne     l22
        inc     r3
l22:
        lda     r1
        sta     r5
        lda     r0
        sta     r4
        inc     r0
        bne     l23
        inc     r1
l23:
        ldy     #0
        lda     (r6),y
        sta     (r4),y
        cmp     #0
        bne     l6
l7:
        rts
Much better code gets generated when slightly rewriting the function:

Code: Select all

void str_cpy(char *s1,char *s2)
{
    char c;
    do{
        c=*s2++;
        *s1++=c;
    }while(c);
}
compiles to:

Code: Select all

;vcprmin=10000
        section text
        global  _str_cpy
_str_cpy:
l7:
        ldy     #0
        lda     (r2),y
        inc     r2
        bne     l15
        inc     r3
l15:
        sta     (r0),y
        inc     r0
        bne     l16
        inc     r1
l16:
        cmp     #0
        bne     l7
        rts
cc65 -Oisr generates:

Code: Select all

.proc   _str_cpy: near

.segment        "CODE"

        jsr     pushax
        jsr     decsp1
L0002:  ldy     #$02
        lda     (sp),y
        tax
        dey
        lda     (sp),y
        sta     regsave
        stx     regsave+1
        clc
        adc     #$01
        bcc     L0007
        inx
L0007:  jsr     staxysp
        ldy     #$00
        lda     (regsave),y
        sta     (sp),y
        ldy     #$04
        lda     (sp),y
        tax
        dey
        lda     (sp),y
        sta     regsave
        stx     regsave+1
        clc
        adc     #$01
        bcc     L0009
        inx
L0009:  jsr     staxysp
        ldy     #$00
        lda     (sp),y
        sta     (regsave),y
        lda     (sp),y
        bne     L0002
        jmp     incsp5

.endproc
Looks like your compiler analizes call tree and places parameters in global variables if possible. Is it true?
It uses zero page locations as registers and passes parameters in a number of registers. But the calling convention is using a fixed ABI (unless the function call is inlined in which case the parameters are used directly).
But does it support recursion?
Yes, for example samples/calc.c uses recursion.
If yes, what code will be generated if parameters will be in stack?
Adding some dummy parameters to the memcpy example will force the parameters onto the stack:

Code: Select all

void memcpy_s(int d1,int d2,int d3,int d4,char *d,char *s,unsigned int n)
{
  while(n){*d++=*s++;n--;}
}
The generated code now has to pull the arguments from the software stack into registers:

Code: Select all

;vcprmin=10000
        section text
        global  _memcpy_s
_memcpy_s:
        ldy     #5
        lda     (sp),y
        sta     r5
        dey
        lda     (sp),y
        sta     r4
        dey
        lda     (sp),y
        sta     r3
        dey
        lda     (sp),y
        sta     r2
        dey
        lda     (sp),y
        sta     r1
        dey
        lda     (sp),y
        sta     r0
        lda     r5
        bne     l22
        lda     r4
        beq     l9
l22:
l8:
        ldy     #0
        lda     (r2),y
        sta     (r0),y
        inc     r2
        bne     l23
        inc     r3
l23:
        inc     r0
        bne     l24
        inc     r1
l24:
        lda     r4
        bne     l25
        dec     r5
l25:
        dec     r4
        lda     r5
        bne     l8
        lda     r4
        bne     l8
l9:
        rts[/quote]

vbc
Posts: 3
Joined: Sun Jun 21, 2020 5:03 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc » Tue Jun 30, 2020 3:53 am

Nikku4211 wrote:
Sat Jun 27, 2020 10:57 am
Nice. Do you plan to support SNES? I know there's already PVSNESLib, but it's not really great to be honest...
If there is some demand I might add support for the 65816, but somebody would have to help with target integration and provide SNES-specific support libraries.

User avatar
aa-dav
Posts: 54
Joined: Tue Apr 14, 2020 9:45 pm
Location: Russia

Re: VBCC Optimizing C-compiler now supports NES

Post by aa-dav » Tue Jun 30, 2020 5:56 am

vbc wrote:
Tue Jun 30, 2020 3:53 am
...
I see. Very good results! Especially if stack is not needed.
Stack variables and parameters are bad thing for 8-bit processors, so I whould recommend to optimize leaf-node functions to do not use stack at all.
Mentioned earlier KickC-compiler (http://forums.nesdev.com/viewtopic.php?f=2&t=20187) brokes compatibility with C by removing of recursion to do not have to deal with software stack. And this is interesting move because manual assembler programming for this machine in fact uses same approach to increase speed and decrease size.
CC65 sometimes generates very long and slow code for compatibility reasons and there are strong recommendations to avoid stack variables.
However leaf-node functions and functions calling only leaf-node functions can be organized in optimal way (not using stack as all) if recursion is not needed and call-stack-tree allows it.
It's really interesting task to speed up things on this machines.
Good luck with your work!

User avatar
Nikku4211
Posts: 26
Joined: Sun Dec 15, 2019 1:28 pm
Location: Bronx, New York
Contact:

Re: VBCC Optimizing C-compiler now supports NES

Post by Nikku4211 » Wed Jul 01, 2020 11:10 am

vbc wrote:
Tue Jun 30, 2020 3:53 am
If there is some demand I might add support for the 65816, but somebody would have to help with target integration and provide SNES-specific support libraries.
SNES-specific support libraries? Like, ASM libraries?

I know a pretty good SNES-specific library... Behold, Optiroc's LibSFX.
I have an ASD, so empathy is not natural for me. If I hurt you, I apologise.

Post Reply