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

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

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc » Tue Dec 22, 2020 12:47 pm

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: Mon Jul 27, 2020 1:14 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by yaros » 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

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

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc » Wed Dec 30, 2020 7:02 pm

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: Mon Jul 27, 2020 1:14 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by yaros » Thu Dec 31, 2020 3:55 pm

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: 67
Joined: Sun Jun 21, 2020 5:03 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc » Wed Jan 06, 2021 6:09 am

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: Mon Jul 27, 2020 1:14 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by yaros » Fri Feb 19, 2021 7:28 pm

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: 10463
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: VBCC Optimizing C-compiler now supports NES

Post by lidnariq » Fri Feb 19, 2021 8:54 pm

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: 8027
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: VBCC Optimizing C-compiler now supports NES

Post by rainwarrior » Sat Feb 20, 2021 4:54 am

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: 67
Joined: Sun Jun 21, 2020 5:03 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc » Tue Feb 23, 2021 7:52 am

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: 22335
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 » Tue Feb 23, 2021 8:35 am

vbc wrote:
Sat Jul 18, 2020 3:48 am
For 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: 67
Joined: Sun Jun 21, 2020 5:03 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc » Tue Feb 23, 2021 7:17 pm

tepples wrote:
Tue Feb 23, 2021 8:35 am
vbc wrote:
Sat Jul 18, 2020 3:48 am
For 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.

Post Reply