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

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 Dec 21, 2020 10:31 am Dr. Volker, is there any way to figure out what exactly vlink is complaining about with the following error?

Error 35: rpg.nes (text+0x2891): Calculated value 0x300 doesn't fit into relocation type R_ABS (offset=0, size=8, mask=0xffffffffffffffff).

edit: Ah, nevermind. I allocated the variable in bss, and imported it in c as zpage. It would be nice if linker could report the symbol (or address) it fails to reference.
The address was apparently 0x300. If you generate a mapfile using -Mmapfile, you get a section table that should enable you to translate text+0x2891 to the object file and offset the relocation originates from. That might also help a bit.

I just checked that for an absolute symbol, vlink displays a nicer error message that includes the symbol name and file name. I will ask Frank if it is possible to improve this error message as well.
yaros
Posts: 47
Joined: Tue Aug 28, 2018 8:54 am

Re: VBCC Optimizing C-compiler now supports NES

Post by yaros »

I think I found another bug.

Function here

Code: Select all

void ppu_SetAddr(__reg("a/x")uint16 addr) =
    "   ldy PPUSTATUS\n"
    "   stx PPUADDR\n"  
    "   sta PPUADDR\n";
Then usage

Code: Select all

ppu_SetAddr(0x2000);
Assembly. Looks like LDA #$20 is being optimized out. Also "LDA #$00 TAX" could be simply "LDX #$00"

Code: Select all

  LDA #$00                 
  TAX                      
  LDY PPUSTATUS
  STA PPUADDR
  STX PPUADDR
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 Dec 29, 2020 7:40 pm I think I found another bug.

Function here

Code: Select all

void ppu_SetAddr(__reg("a/x")uint16 addr) =
    "   ldy PPUSTATUS\n"
    "   stx PPUADDR\n"  
    "   sta PPUADDR\n";
Then usage

Code: Select all

ppu_SetAddr(0x2000);
Assembly. Looks like LDA #$20 is being optimized out. Also "LDA #$00 TAX" could be simply "LDX #$00"

Code: Select all

  LDA #$00                 
  TAX                      
  LDY PPUSTATUS
  STA PPUADDR
  STX PPUADDR
Can you produce a small example that generates this code? I tried to create a small test file but could not reproduce the problem.

The x register holds the high-byte, therefore the code does not look like an lda #$20 has been removed (that would come before the tax). vbcc seems to load 0x0000.
yaros
Posts: 47
Joined: Tue Aug 28, 2018 8:54 am

Re: VBCC Optimizing C-compiler now supports NES

Post by yaros »

On a small example it does look like this.

Code: Select all

  LDA #$20                 
  TAX                      
  LDA #$00                 
  LDY PpuStatus_2002       
  STX PpuAddr_2006         
  STA PpuAddr_2006          
I also wrote bunch of code since then, so now I can't reproduce it. Not sure what exact combination of optimizations caused this.

Is it deeply embedded in the compiler to load immediate values trough A register? E.g. using lda/tax instead of ldx or is it just lack of optimizations in the 6502 backend?

I've also noticed sometimes there are not enough register optimizations that result in the code that looks something like.

Code: Select all

lda r3
sta r5
; nothing touches both of those registers
lda r5
sta r3
; do work with r3
I tried to poke around machines/6502 to see if I could do something useful there, but it's full of abbreviations and it would take a while to figure out what's going on there..
vbc
Posts: 72
Joined: Sun Jun 21, 2020 5:03 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc »

yaros wrote: Thu Dec 31, 2020 3:55 pm Is it deeply embedded in the compiler to load immediate values trough A register? E.g. using lda/tax instead of ldx or is it just lack of optimizations in the 6502 backend?
Just a missing optimization in the backend for a special case. I already fixed this for the next version.
I've also noticed sometimes there are not enough register optimizations that result in the code that looks something like.

Code: Select all

lda r3
sta r5
; nothing touches both of those registers
lda r5
sta r3
; do work with r3
I would have to reproduce this to tell the exact reason, but there surely are cases where non-optimal code is generated.
yaros
Posts: 47
Joined: Tue Aug 28, 2018 8:54 am

Re: VBCC Optimizing C-compiler now supports NES

Post by yaros »

I found either nasty bug or nasty C compliant behavior.

Code: Select all

signed char a[10];
int main()
{
    for(unsigned char i = 0; i < 10; i++) {
        a[i] = 0xFF;
    }
    for(unsigned char i = 0; i < 10; i++) {
        if(a[i] == 0xFF) {  // <<-- relevant line here
            break;
        }
    }
    for(;;);
}
Generated code loads

Code: Select all

a[i] 
and if it is positive (in 2's compliment), it compares it with 0xff (which doesn't make sense), but if it is negative, it simply skips the compassion altogether.

Code: Select all

  LDA _a,Y                 
  BPL IfPositive                  
  DEX                      
IfPositive:                     
  CPX #$00                 
  BNE IfNegative                  
  CMP #$FF                 
  BEQ l27                  
IfNegative:                     
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

Re: VBCC Optimizing C-compiler now supports NES

Post by lidnariq »

yaros wrote: Fri Feb 19, 2021 7:28 pm nasty C compliant behavior.
Type promotions are endless pain. I believe this is standards-compliant.
User avatar
rainwarrior
Posts: 8734
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: VBCC Optimizing C-compiler now supports NES

Post by rainwarrior »

To clarify:

Code: Select all

// 0xFF is being implicitly converted here, even though the stored result is identical.
a[i] = 0xFF; // a[i] = -1 (signed char), not 0xFF
a[i] = 255; // this has the same meaning

// 0xFF is not a signed char
// So it has to become a wider type (16-bit signed int) for comparison against that.
a[i] == 0xFF
a[i] == 0x00FF // this is what you're really asking for

; this code extends the sign of a[i] into a 16-bit signed int as X:A
ldx #0
lda _a, Y
bpl IfPositive
dex
IfPositive:

; so at this point (unsigned) X:A = $FFFF because the widening conversion had to extend its sign.
cpx #$00 ; compare the high byte against 0x00FF high byte
bne IfNegative
cmp #$FF ; compare the low byte against 0x00FF low byte
So, the generated code looks correct to me. The problem is that 0xFF is not in the range of a signed char, but can get silently converted in a way you didn't expect here. Use -1 instead.

Code: Select all

// not actually a problem even though it's a conversion,
// you get the -1 you expect from the implicit conversion
a[i] = 0xFF;
 
// this is the problem
// since the right side isn't being explicitly truncated, it has to become an int
a[i] == 0xFF
 
a[i] == (signed char)0xFF // one way to fix it with an explicit truncation
a[i] == -1 // another way to fix it by using a matching signed type
vbc
Posts: 72
Joined: Sun Jun 21, 2020 5:03 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc »

I have uploaded a new version: http://www.compilers.de/vbcc.html

Major changes since last update:

- new target: MEGA65 (native mode, some banking support)
- new target: Commander X16 (thanks András Péteri)
- new options -prefer-statics/-force-statics (allocate local variables in static memory rather than on the stack)
- new option -range-opt (first implementation of some range-based optimizations changing induction variables to smaller types)
- added support for o65 object file format
- added support for Oric target format
- better use of x register
- improved cross-module function-inlining
- IEEE math library works with 65c02
- several code generation improvements
- fixed several bugs
- slightly reworked examples
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: VBCC Optimizing C-compiler now supports NES

Post by tepples »

vbc wrote: Sat Jul 18, 2020 3:48 amFor non-commercial use you can include it without restrictions. For commercial use of vbcc please contact me.
In a request for a license for use of vbcc to build an NES game intended for distribution on cartridge, what information do you require?
vbc
Posts: 72
Joined: Sun Jun 21, 2020 5:03 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc »

tepples wrote: Tue Feb 23, 2021 8:35 am
vbc wrote: Sat Jul 18, 2020 3:48 amFor non-commercial use you can include it without restrictions. For commercial use of vbcc please contact me.
In a request for a license for use of vbcc to build an NES game intended for distribution on cartridge, what information do you require?
The simplest case would be a single-user license bought for one specific target system (here NES) as is (i.e. no guaranteed support included). Then I just need to know name and location. For a retro-system and one developer, I would price this between $50-$100, I think.
vbc
Posts: 72
Joined: Sun Jun 21, 2020 5:03 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc »

I have uploaded version 3 of the vbcc distribution for 6502 targets at http://www.compilers.de/vbcc.html

Major changes since last update:
  • several bug fixes
  • improved code generation
  • linker mask optimizations to reduce overhead of some library functions (still much room for improvement)
  • improved attribute checks for banking
  • C64 new features:
    • stdio functions allow file access on 1541 compatible drives
  • MEGA65 new features:
    • free license for commercial usage
    • code generator uses 32bit extensions
    • code generator uses HW multiplier
    • full automated banking support
    • ROM-less library enabling full use of the entire RAM
    • stdio functions allow reading of files on SD card
  • BBC new features:
    • stdio functions allow file access
    • full automated banking support for systems with sideways RAM
    • support for command line arguments
    • configuration for clean return after exit
  • CBM PET new features:
    • added as new target
We are happy to announce that the Museum of Electronic Games & Art e.V. (http://www.m-e-g-a.org) has decided to sponsor the MEGA65 version of vbcc.
This does not only help us to continue supporting and improving this port but it also allows us to relax the terms of use for the MEGA65 community. Everyone may now freely use vbcc to develop MEGA65 code for commercial as well as non-commercial usage (for details please refer to the license in the documentation).

We thank MEGA e.V. for the confidence in vbcc and hope that this step will help in the creation of new software for the MEGA65.
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 »

I need some help figuring out how to make a static library.

I'm working on porting shiru's neslib to vbcc6502. It's not finished yet, but I'm starting to get some working results now. One of the upcoming steps that I haven't been able to figure out, is how to take these multiple .o files to make a libneslib.a file.

I'm getting the .o files by using the -c option with vc. But I don't know if there's supposed to be more to that step, or what the next step is. Here are the commands I'm using to build, clearly I'm doing something wrong with vlink:

Code: Select all

vc +nrom256v crt0.s neslib.s oam_spr.s oam_meta_spr.s pad.s split.s splitxy.s rand.s vram_unrle.s memfill.s oam_clear_fast.s -c

vlink -Bstatic crt0.o neslib.o oam_spr.o oam_meta_spr.o pad.o split.o splitxy.o rand.o vram_unrle.o memfill.o oam_clear_fast.o -o libtest.a
Fatal error 149: Mismatching target address sizes in input/output formats.
Aborting.
To be clear, everything works when I use vc and add an example file with main(), and compile it all together. I've gotten a constructor to work (_INIT for a cut-down version of neslib's crt0.s), I've taken over NMI and IRQ vectors, and it builds OK with the vbcc's included nrom256v config so far. It's just that I eventually want to include it with "vc -lneslib".
vbc
Posts: 72
Joined: Sun Jun 21, 2020 5:03 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc »

Memblers wrote: Fri Jun 09, 2023 1:52 am I need some help figuring out how to make a static library.
The static libraries are simply ar-archives of object files like on many Unix/Linux systems. If you are working on such a system you probably have ar already installed. There is e.g. an implementation in the GNU binutils. I think some of the GUI archivers on Windows might also support that format.

If you create an such an archive called libxyz.a you can link it using -lxyz. For every unresolved external, vlink will then link the first object providing it from the lib.
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! It works now. I have MinGW installed, and grabbed the the ar.exe utility from there.
Post Reply