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

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc » Sun Jul 19, 2020 4:09 am

Oziphantom wrote:
Sun Jul 19, 2020 12:24 am
The 65C02 can not move the ZP.
You are right. Apparently it was added for the 6280.

User avatar
Banshaku
Posts: 2393
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

Re: VBCC Optimizing C-compiler now supports NES

Post by Banshaku » Sun Jul 19, 2020 6:14 am

vbc wrote:
Sun Jul 19, 2020 4:05 am
What should they do? How would they differ from ADDR and SIZEOF?
Good question. From what I saw in the examples from lazycow, ADDR is the address of the section (and it may be inside another section too) and sizeof is the size of what was declared inside the section but not of the actual size of the memory area so if there is little code/data it it, it won't span the size of the memory area.

With ORIGIN/LENGTH, if I understood properly, I could do something like this (just a quick example written, maybe error in it and for the sake of argument):

Code: Select all

MEMORY
{
  out:       org=0,      len=0xffffff
  ZP:        org=0,      len=0x0100
  OAM:       org=0x0200, len=0x0100
  ROM:       org=0x8000, len=0x8000
  CHR:       org=0x0000, len=0x2000
  RAM:       org=0x0300, len=0x0500
}
SECTIONS
{
  prg_rom: {
    *(code);       /* program code */
    *(rodata);     /* read only data, (not used in sample) */
    . = ORIGIN(ROM) + LENGTH(ROM) - SIZEOF(vectors);   /* move at end of bank minus vector size, don't need to hard-code  0x0FFFA */
    *(vectors);    /* put vectors at the end */
  } >ROM AT>out

  chr_rom:  {
     *(chars);     /* segment with all chr data */
     .= 0x2000;
  } >CHR AT>out

  /* RAM related section management */
  zpage (NOLOAD) : {*(zpage)} >ZP
  OAM_BUFFER (NOLOAD) : {*(OAM_BUFFER)} >OAM
  bss (NOLOAD): {*(bss)} >RAM

  /* VBCC specific for stack and heap */
  __STACK = 0x800;

  ___heap = ADDR(bss) + SIZEOF(bss);
  ___heapend = __STACK;  
}
I can tell to move the cursor at the end of memory area for this section. That seems better than harcoding what is actually defined in the memory area or the current example were it define the total size of the bank and remove litte by little to find the end. If one section in that bank or very little it is fine but if you have multiple one you shouldn't need to do that and let the linker move it to the end. Another way seems to fill the section by adding fill at the end but this is not yet supported with vlink at the moment so the ORIGIN/LENGTH seems the simplest one, if they would exist. It just return values from MEMORY to use later.

For now I just hardcode the value for the cursor and it's working fine. I will now soon if any issue arise once I test multi banking for MMC3. I'm at stage 3 now, mm3 and soon to port more code to it.

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

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc » Sun Jul 19, 2020 12:25 pm

Banshaku wrote:
Sun Jul 19, 2020 6:14 am
With ORIGIN/LENGTH, if I understood properly, I could do something like this (just a quick example written, maybe error in it and for the sake of argument):

Code: Select all

MEMORY
{
  out:       org=0,      len=0xffffff
  ZP:        org=0,      len=0x0100
  OAM:       org=0x0200, len=0x0100
  ROM:       org=0x8000, len=0x8000
  CHR:       org=0x0000, len=0x2000
  RAM:       org=0x0300, len=0x0500
}
SECTIONS
{
  prg_rom: {
    *(code);       /* program code */
    *(rodata);     /* read only data, (not used in sample) */
    . = ORIGIN(ROM) + LENGTH(ROM) - SIZEOF(vectors);   /* move at end of bank minus vector size, don't need to hard-code  0x0FFFA */
    *(vectors);    /* put vectors at the end */
  } >ROM AT>out

  chr_rom:  {
     *(chars);     /* segment with all chr data */
     .= 0x2000;
  } >CHR AT>out

  /* RAM related section management */
  zpage (NOLOAD) : {*(zpage)} >ZP
  OAM_BUFFER (NOLOAD) : {*(OAM_BUFFER)} >OAM
  bss (NOLOAD): {*(bss)} >RAM

  /* VBCC specific for stack and heap */
  __STACK = 0x800;

  ___heap = ADDR(bss) + SIZEOF(bss);
  ___heapend = __STACK;  
}
But the memory regions are fixed anyway, so you can just use symbols to define them:

Code: Select all

ROM_ORG = 0x8000;
ROM_LEN = 0x8000;

MEMORY
{
  ...
  ROM: org = ROM_ORG, len = ROM_LEN
  ...
}
Now you can use ROM_ORG instead of ORIGIN(ROM) and ROM_LEN instead of LENGTH(ROM).
Another way seems to fill the section by adding fill at the end but this is not yet supported with vlink at the moment
You can use RESERVE(n) to fill n bytes. This works at the end of a section.

rox_midge
Posts: 89
Joined: Mon Sep 19, 2005 11:51 am

Re: VBCC Optimizing C-compiler now supports NES

Post by rox_midge » Sun Jul 19, 2020 12:46 pm

Banshaku wrote:
Fri Jul 17, 2020 5:33 pm
I'm calling vbcc6502 directly and passing parameters with registers is working well with my makefile so it should have worked. If you are curious to know how to use it directly, try to compile with vc -vv and it will show you all the parameters it used. Maybe one of them was missing. Still, if for you vc does the job then calling directly is maybe not necessary since some parameters are not the same and VC frontend take care of them (-O is an example of the one that differ).
It turns out that was my problem - I was calling vbcc6502 with -O=3, which doesn't apply enough optimization to use the ZP registers. Using -O=991, which is what vc uses, does inline the registers. Thanks!

Since I'm not using nrom or unrom, it looks like I'll have to create my own config file and linker script. My cc65 project is currently using mapper 4 with 128KB of PRG-ROM, no CHR-ROM, 8KB of PRG-RAM, and 64KB of CHR-RAM. I've bodged up the vbcc vlink script to generate the proper iNES 2.0 header with these extended fields, but right now I'm struggling to understand the format of the linker script so that I can port over the rest of my cc65 project.

User avatar
Banshaku
Posts: 2393
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

Re: VBCC Optimizing C-compiler now supports NES

Post by Banshaku » Sun Jul 19, 2020 5:18 pm

vbc wrote:
Sun Jul 19, 2020 12:25 pm
But the memory regions are fixed anyway, so you can just use symbols to define them:
Since the only documentation available on how to use (unless mistaken) is gnu linker that should be used as a reference and from what I read you cannot use symbols to set MEMORY, I wasn't aware that vlink allows it (maybe it is mentioned in the vlink doc and I missed it, I will try to confirm later). I will try it but I still think if you define it in MEMORY, you shouldn't need to use symbols after since the information is all in memory and to keep to some degree compatibility with GNU linker. For now it's a good compromise if I can use that way.
vbc wrote:
Sun Jul 19, 2020 12:25 pm
You can use RESERVE(n) to fill n bytes. This works at the end of a section.
What is the difference between reserving N byte and just moving the cursor at the end? If I know the location of the end of MEMORY, I don't need to figure how how many bytes are left to fill by calculating the size of every section and it should simplify it. I will check the doc, maybe there is something about reserve that is different that I'm not aware of.

Thank you again for the information, it's moving forward quite well.

Edit:

I rechecked the complete doc of vlink and there is no mention that you can use symbol in MEMORY. It just say to use gnu linker as a doc and here was the doc says:
The origin is an numerical expression for the start address of the memory region. The expression must evaluate to a constant and it cannot involve any symbols. The keyword ORIGIN may be abbreviated to org or o (but not, for example, ORG).

The len is an expression for the size in bytes of the memory region. As with the origin expression, the expression must be numerical only and must evaluate to a constant. The keyword LENGTH may be abbreviated to len or l.
Both says " The expression must evaluate to a constant and it cannot involve any symbols.". If vlink support to use symbols then it should be documented in the doc since gnu doesn't do that. For them, a constants string AAAA = 1234 is a symbol and there was a discussion on the net about this issue.

By browsing the doc, I found something of interest. There is an option to output to a file a group of sections by defining a segment with PHDR. Since it seems easier to do than doing -osec and more strict to which to ouput, I may have questions on how to do it later. With -osec, if for some reason I create many sections they will all be generating files, which is not ideal.
Last edited by Banshaku on Sun Jul 19, 2020 7:59 pm, edited 1 time in total.

User avatar
Banshaku
Posts: 2393
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

Re: VBCC Optimizing C-compiler now supports NES

Post by Banshaku » Sun Jul 19, 2020 5:22 pm

rox_midge wrote:
Sun Jul 19, 2020 12:46 pm
It turns out that was my problem - I was calling vbcc6502 with -O=3, which doesn't apply enough optimization to use the ZP registers. Using -O=991, which is what vc uses, does inline the registers. Thanks!
This was my guess about the possible error, wrong parameter or missing one. The parameters are not the same and it is explained in the doc.
rox_midge wrote:
Sun Jul 19, 2020 12:46 pm
Since I'm not using nrom or unrom, it looks like I'll have to create my own config file and linker script. My cc65 project is currently using mapper 4 with 128KB of PRG-ROM, no CHR-ROM, 8KB of PRG-RAM, and 64KB of CHR-RAM. I've bodged up the vbcc vlink script to generate the proper iNES 2.0 header with these extended fields, but right now I'm struggling to understand the format of the linker script so that I can port over the rest of my cc65 project.
I'm starting to create a sample for MMC3 (mapper 4) with PRG/CHR ROM so once I have something working, I will let you know.

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 » Mon Jul 20, 2020 12:06 am

Image Image

Hi, I made a small Q&D test for mapper4/MMC3/TBROM: mapper4.zip
(source and cartridge binary included, see buildtests.sh how to compile)
It only uses manual bankswitching instead of vbcc6502's cool auto bankswitching feature. So it might need some additional tweaking. But it's a start.

rox_midge
Posts: 89
Joined: Mon Sep 19, 2005 11:51 am

Re: VBCC Optimizing C-compiler now supports NES

Post by rox_midge » Mon Jul 20, 2020 5:53 am

Lazycow wrote:
Mon Jul 20, 2020 12:06 am
Hi, I made a small Q&D test for mapper4/MMC3/TBROM: mapper4.zip
(source and cartridge binary included, see buildtests.sh how to compile)
It only uses manual bankswitching instead of vbcc6502's cool auto bankswitching feature. So it might need some additional tweaking. But it's a start.
Ah! That's really helpful. I see now how you're filling up the different banks in the .cmd file, and reserving the final bank for the code, and how to use the different methods (__section, __bank, #pragma) to specify the place each of them belongs. If push comes to shove I can probably just have my resource processor spit out huge const sections for the data that needs to be embedded into each bank.

FWIW, here's the header modifications I made to support the iNES 2.0 fields that weren't present in the original. It doesn't support miscellaneous ROMs or expansion devices, mostly because I don't know what those are, but all of the other fields should work correctly, specifically the PRG-RAM and CHR-RAM sizes. The comments can probably come out, but they're harmless and they explain what's going on in each field.

Code: Select all

MEMORY
{
  /* ... */
}

INES_MAPPER = 4 ; /* The iNES mapper number */
INES_SUBMAPPER = 0 ; /* The submapper number, if needed */

INES_PRG_BANKS = 8 ; /* Number of 16K PRG banks, change to 2 for NROM256 */
INES_CHR_BANKS = 0 ; /* number of 8K CHR banks */
INES_MIRRORING = 0 ; /* 0 horizontal, 1 vertical, 8 four screen */

INES_V20 = 1 ; /* Use NES 2.0 header format?  Note: if this is 0, most of the following flags are ignored. */

INES_USE_4SCREEN = 0 ;
INES_HAS_TRAINER = 0;
INES_HAS_BATTERY_RAM = 0;
INES_CONSOLE_TYPE = 0;

/*
  RAM sizes are expressed according to the following:
   0 = 0 bytes
   1 = 128 bytes
   2 = 256 bytes
   3 = 512 bytes
   4 = 1,024 bytes
   5 = 2,048 bytes
   6 = 4,096 bytes
   7 = 8,192 bytes
   8 = 16,384 bytes
   9 = 32,768 bytes
  10 = 65,536 bytes
  11 = 131,072 bytes
  12 = 262,144 bytes
  13 = 524,288 bytes
  14 = 1,048,576 bytes
  15 = reserved (do not use)
*/

INES_PRG_NVRAM_SIZE = 0;
INES_PRG_RAM_SIZE = 7; /* 8KB PRG-RAM */

INES_CHR_NVRAM_SIZE = 0;
INES_CHR_RAM_SIZE = 10 ; /* 64KB CHR-RAM */

INES_IS_PAL = 0;
INES_BOTH_PAL_AND_NTSC = 0;

INES_VS_CPU_BITS = 0;
INES_VS_PPU_BITS = 0;

SECTIONS
{
  header:
  {
    /* iNES header - comments directly from https://wiki.nesdev.com/w/index.php/NES_2.0 */
    /* 0-3: Identification String. Must be "NES<EOF>". */
    BYTE(0x4e);BYTE(0x45);BYTE(0x53);BYTE(0x1a);

    /* 4: PRG-ROM size LSB */
    BYTE(INES_PRG_BANKS);

    /* 5: CHR-ROM size LSB */
    BYTE(INES_CHR_BANKS);

    /* 6: Flags 6
       D~7654 3210
         ---------
         NNNN FTBM
         |||| |||+-- Hard-wired nametable mirroring type
         |||| |||     0: Horizontal or mapper-controlled
         |||| |||     1: Vertical
         |||| ||+--- "Battery" and other non-volatile memory
         |||| ||      0: Not present
         |||| ||      1: Present
         |||| |+--- 512-byte Trainer
         |||| |      0: Not present
         |||| |      1: Present between Header and PRG-ROM data
         |||| +---- Hard-wired four-screen mode
         ||||        0: No
         ||||        1: Yes
         ++++------ Mapper Number D0..D3
    */
    BYTE(((INES_MAPPER & 0x0f) << 4) | ((INES_USE_4SCREEN & 0x01) << 3) | ((INES_HAS_TRAINER & 0x01) << 2) | ((INES_HAS_BATTERY_RAM & 0x01) << 1) | ((INES_MIRRORING & 0x01) << 0));

    /* 7: Flags 7
       D~7654 3210
         ---------
         NNNN 10TT
         |||| ||++- Console type
         |||| ||     0: Nintendo Entertainment System/Family Computer
         |||| ||     1: Nintendo Vs. System
         |||| ||     2: Nintendo Playchoice 10
         |||| ||     3: Extended Console Type
         |||| ++--- NES 2.0 identifier
         ++++------ Mapper Number D4..D7
    */
    BYTE(((INES_MAPPER >> 4) & 0x0f) | ((INES_V20 & 0x01) << 3) | (INES_CONSOLE_TYPE & 0x03));
 
    /* 8: Mapper MSB/Submapper
       D~7654 3210
         ---------
         SSSS NNNN
         |||| ++++- Mapper number D8..D11
         ++++------ Submapper number
    */
    BYTE((((INES_SUBMAPPER * (INES_V20 & 0x01)) & 0x0f) << 4) | (((INES_MAPPER * (INES_V20 & 0x01)) >> 8) & 0x0f));

    /* 9: PRG-ROM/CHR-ROM size MSB
       D~7654 3210
         ---------
         CCCC PPPP
         |||| ++++- PRG-ROM size MSB
         ++++------ CHR-ROM size MSB
    */
    BYTE((((INES_CHR_BANKS * (INES_V20 & 0x01)) >> 4) & 0xf0) | (((INES_PRG_BANKS * (INES_V20 & 0x01)) >> 8) & 0x0f));

    /* 10: PRG-RAM/EEPROM size
       D~7654 3210
         ---------
         pppp PPPP
         |||| ++++- PRG-RAM (volatile) shift count
         ++++------ PRG-NVRAM/EEPROM (non-volatile) shift count
       If the shift count is zero, there is no PRG-(NV)RAM.
       If the shift count is non-zero, the actual size is
       "64 << shift count" bytes, i.e. 8192 bytes for a shift count of 7.
    */
    BYTE((((INES_PRG_NVRAM_SIZE * (INES_V20 & 0x01)) & 0x0f) << 4) | (((INES_PRG_RAM_SIZE * (INES_V20 & 0x01)) & 0x0f) << 0));

    /* 11: CHR-RAM size
       D~7654 3210
         ---------
         cccc CCCC
         |||| ++++- CHR-RAM size (volatile) shift count
         ++++------ CHR-NVRAM size (non-volatile) shift count
       If the shift count is zero, there is no CHR-(NV)RAM.
       If the shift count is non-zero, the actual size is
       "64 << shift count" bytes, i.e. 8192 bytes for a shift count of 7.
    */
    BYTE((((INES_CHR_NVRAM_SIZE * (INES_V20 & 0x01)) & 0x0f) << 4) | (((INES_CHR_RAM_SIZE * (INES_V20 & 0x01)) & 0x0f) << 0));
    
    /* 12: CPU/PPU Timing
       D~7654 3210
         ---------
         .... ..VV
                ++- CPU/PPU timing mode
                     0: RP2C02 ("NTSC NES")
                     1: RP2C07 ("Licensed PAL NES")
                     2: Multiple-region
                     3: UMC 6527P ("Dendy")
    */
    BYTE((((INES_IS_PAL * (INES_V20 & 0x01)) & 0x01) << 0) | (((INES_BOTH_PAL_AND_NTSC * (INES_V20 & 0x01)) & 0x01) << 1));

    /* 13: When Byte 7 AND 3 =1: Vs. System Type
       D~7654 3210
         ---------
         MMMM PPPP
         |||| ++++- Vs. PPU Type
         ++++------ Vs. Hardware Type

       When Byte 7 AND 3 =3: Extended Console Type
       D~7654 3210
         ---------
         .... CCCC
              ++++- Extended Console Type
    */
    BYTE((((INES_VS_CPU_BITS * (INES_V20 & 0x01)) & 0x0f) << 4) | (((INES_VS_PPU_BITS * (INES_V20 & 0x01)) & 0x0f) << 0));

    /* 14: Miscellaneous ROMs
       D~7654 3210
         ---------
         .... ..RR
                ++- Number of miscellaneous ROMs present
    */
    BYTE(0);

    /* 15: Default Expansion Device
       D~7654 3210
         ---------
         ..DD DDDD
           ++-++++- Default Expansion Device
    */
    BYTE(0);
  } >out

  /* ... */
}

Banshaku wrote:
Fri Jul 17, 2020 9:16 am
My second sample is now working fine and is:
- not using libvc, to test if works fine nes only or not
- removed ctor/dtor and no issue, like you said
- uses my own init code in startup
- uses custom nmi changable at runtime
Can you share this, specifically the custom init code for startup? My compilation currently fails because the zero-page registers aren't defined, and I don't want to include the existing (binary) startup code, because I don't know what's in it.

User avatar
Banshaku
Posts: 2393
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

Re: VBCC Optimizing C-compiler now supports NES

Post by Banshaku » Mon Jul 20, 2020 6:40 am

rox_midge wrote:
Mon Jul 20, 2020 5:53 am
Can you share this, specifically the custom init code for startup? My compilation currently fails because the zero-page registers aren't defined, and I don't want to include the existing (binary) startup code, because I don't know what's in it.
I will share it eventually once I figure out all the things that seems not clear and I'm really close to it.

If you just need to define the zero pages variables, Vbc shared on his site a new version with the startup code that is not compiled so that should already help you to figure out what is missing in your case.

What I'm making is with a very specific goal:
- reduce the footprint to strict minimum but at the cost of not using the C library (for game, that is not an issue)
- create a makefile that take care of dependencies and allow to just copy your source in any folder in SRC wihtout any settings
- include .h without the need to specify the path
- use my own custom startup code to allow dynamic IRQ/NMI
- figure out the linker file for mmc3 and other banking
- test banking with previous code

Other things that I have done is the header is now in it's own file so you don't need to do it in the linker but in a .s file, which is easier to do. The PRG/CHR are splits in their own file (working for NROM, not sure for MMC3 linker script yet) and at the end header/prg/chr are combined back together. This means that you have the raw files to write to your eprom and a nes file for testing in emulator.

Since I use my own makefile, if you want to continue to use vc directly, you will have to:
- build your own startup file with vasm
- create a custom config script or replace the startup file with your own (better to make your own config)

Once all my tests are over I should be able to share a NROM, MMC3 and maybe remake the UROM512 with the same fonctionality and share it on github. Not sure when yet since I'm learning along the way and the script is improving, which means older ones will need to be updated.

I think vbc shared before but here's the link with the startup library:
http://www.ibaug.de/vbcc/vbcc6502_2a.zip

There is more than the startup, all the code for banking with unrom512 so that vbcc can uses far pointers is included too.

As for what's is it (startup code), it is basically:
- banking code for unrom
- some copy code for CHR-RAM (copy chr to chr ram)
- some bank copy code
- basic nes init,ram, oam, C stack, zero page varaibles, vector table inside startup and settings to copy BSS from ROM
- startupu is for unrom and chr-ram (use the code mentioned above)
- some nmi routines to be used with the library lazynes
- code for main args
- some constants for nes
- some read/write code optimized for a specific case

I think that sums it up. To use and make your own version, I would suggest to go through all the files and understand what they do. Without doing that, you won't really now what is necessary.

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

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc » Mon Jul 20, 2020 2:39 pm

Banshaku wrote:
Sun Jul 19, 2020 5:18 pm
vbc wrote:
Sun Jul 19, 2020 12:25 pm
You can use RESERVE(n) to fill n bytes. This works at the end of a section.
What is the difference between reserving N byte and just moving the cursor at the end? If I know the location of the end of MEMORY, I don't need to figure how how many bytes are left to fill by calculating the size of every section and it should simplify it. I will check the doc, maybe there is something about reserve that is different that I'm not aware of.
RESERVE will fill the space even if there is no data after it and it also works if n==0. We could not get this to work with GNU ld scripts. If you do not have this problem you can just as well use the cursor.
I rechecked the complete doc of vlink and there is no mention that you can use symbol in MEMORY. It just say to use gnu linker as a doc and here was the doc says:
The origin is an numerical expression for the start address of the memory region. The expression must evaluate to a constant and it cannot involve any symbols. The keyword ORIGIN may be abbreviated to org or o (but not, for example, ORG).

The len is an expression for the size in bytes of the memory region. As with the origin expression, the expression must be numerical only and must evaluate to a constant. The keyword LENGTH may be abbreviated to len or l.
Both says " The expression must evaluate to a constant and it cannot involve any symbols.". If vlink support to use symbols then it should be documented in the doc since gnu doesn't do that. For them, a constants string AAAA = 1234 is a symbol and there was a discussion on the net about this issue.
Well, I have to agree with your reading of the GNU ld documentation, but GNU ld does allow constant symbols here, just as vlink does. IMHO it is a problem with the GNU documentation. To be honest, we encountered other instances where the GNU ld documentation is clearly wrong.

Actually, I tried to get Frank to write a specification of the linker scripts in vlink some time ago, but he wanted to avoid it, because it is quite a bit of work. I did convince him to at least add the link to the GNU ld documentation.

I will tell Frank that there seem to be more problems with the GNU documentation and that it is affecting users. Maybe he can come up with a better specification.

User avatar
Banshaku
Posts: 2393
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

Re: VBCC Optimizing C-compiler now supports NES

Post by Banshaku » Tue Jul 21, 2020 12:30 am

vbc wrote:
Mon Jul 20, 2020 2:39 pm
RESERVE will fill the space even if there is no data after it and it also works if n==0. We could not get this to work with GNU ld scripts. If you do not have this problem you can just as well use the cursor.
I see. In my case it seems to work (will know if it still after testing mmc3). I will keep in mind RESERVE if I start to have issues with filling the banks.
vbc wrote:
Mon Jul 20, 2020 2:39 pm
Well, I have to agree with your reading of the GNU ld documentation, but GNU ld does allow constant symbols here, just as vlink does. IMHO it is a problem with the GNU documentation. To be honest, we encountered other instances where the GNU ld documentation is clearly wrong.
I see. Well, nobody likes to update documentation so maybe that part wasn't changed :lol: Some people complained on the net that you couldn't do and the doc is written that way so I assumed that GNU ld always worked that way. Since I have never used it yet and learning it through vlink, I may make a few mistakes along the way ^-^;;
vbc wrote:
Mon Jul 20, 2020 2:39 pm
Actually, I tried to get Frank to write a specification of the linker scripts in vlink some time ago, but he wanted to avoid it, because it is quite a bit of work. I did convince him to at least add the link to the GNU ld documentation.
I don't think it's worth forcing him to update. How many people asked about that? If I'm the only one then either people didn't mind about it or like most people, they just skim most of the doc and don't know about those options. I went through most of the details of the gnu one and it's quite terse and hard to figure out so most people must be never going into in details unless they have to.
vbc wrote:
Mon Jul 20, 2020 2:39 pm
I will tell Frank that there seem to be more problems with the GNU documentation and that it is affecting users. Maybe he can come up with a better specification.
If I'm the only one that asked about that then there is no rush yet ;)

I will continue my mm3 sample and may have question later with the linker. I'm still not sure how PHDR works and how it could help on my project since the gnu doc is focused on ELF and maybe I'm reading too much into it. I would like that "segments" would be blobs that encompass sections so they could be exported to file and not all sections individually. Will experiment and see how it goes.

Thank you again for your time.

edit:

I think my idea I had in mind for segment won't work. What I need to confirm is that you select rawseg instead of rawbin1, each segments generated will contains more information that I think is related to how elf work, is it correct? If this is the case then my idea just went out the windows (using segments to aggregate sections into a specific files and avoid to have 1 section per file like osec).

edit2:

And you were right, the cursor didn't work when I started to create multiple banks, it only saved the data that was included. I need to find the reason why but my guess is if you add an input section after the cursor, in that case it will fill it. Is it by design, specific to GNU LD or vlink, I cannot say, but that is the only logical explanation I can figure out.

At the least RESERVE is working so I will figure out something.

edit3:

I now have a mmc3 example working. I had to use RESERVE since cursor only doesn't work unless content is set after. Since it requires multiple sections compared to NROM I removed osec. I found a way to have the header in external file without the need to embed it in the linker. It is progressing well.

One thing I found is that you need at the least 1 test segment since vbcc may include some code to manage the RX zpage variable (rloadxx/rsavexx). Except for that it's moving forward and just need to clean-up the makefile.

I don't spit the rom anymore since I need to define multiple output sections but for now it's a non issue. If there was a way to have multiple out file that would be great but I don't think the linker does that, unless mistaken. If there is one way to do it, I'm all ears ;)

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

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc » Wed Jul 22, 2020 3:03 am

Lazycow wrote:
Mon Jul 20, 2020 12:06 am
Hi, I made a small Q&D test for mapper4/MMC3/TBROM: mapper4.zip
(source and cartridge binary included, see buildtests.sh how to compile)
It only uses manual bankswitching instead of vbcc6502's cool auto bankswitching feature. So it might need some additional tweaking. But it's a start.
I have created an adapted bankswitching lib from your code. When using those modifications, it should be possible to use automatic bank switching with those mappers. I would like to add this to the next release. Are there any other changes required to support those mappers?
Attachments
mapper4upd.zip
(4.58 KiB) Downloaded 34 times

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

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc » Wed Jul 22, 2020 3:38 am

Banshaku wrote:
Tue Jul 21, 2020 12:30 am
I think my idea I had in mind for segment won't work. What I need to confirm is that you select rawseg instead of rawbin1, each segments generated will contains more information that I think is related to how elf work, is it correct? If this is the case then my idea just went out the windows (using segments to aggregate sections into a specific files and avoid to have 1 section per file like osec).
I have not used rawseg myself, but it does not seem to contain extra information.
And you were right, the cursor didn't work when I started to create multiple banks, it only saved the data that was included. I need to find the reason why but my guess is if you add an input section after the cursor, in that case it will fill it. Is it by design, specific to GNU LD or vlink, I cannot say, but that is the only logical explanation I can figure out.

At the least RESERVE is working so I will figure out something.
Apparently it was specified like that in GNU ld and vlink tries to be compatible. We added RESERVE to get around the problems it causes.
I now have a mmc3 example working. I had to use RESERVE since cursor only doesn't work unless content is set after. Since it requires multiple sections compared to NROM I removed osec. I found a way to have the header in external file without the need to embed it in the linker. It is progressing well.
Is there a reason for splitting the output? Do you want to do some postprocessing on the files?
One thing I found is that you need at the least 1 test segment since vbcc may include some code to manage the RX zpage variable (rloadxx/rsavexx). Except for that it's moving forward and just need to clean-up the makefile.
Yes, all the library code is placed into section text. Multiplication/division or floating point math will also call library functions. You can map them to your own output segments, but the library usually has to be placed into non-banked memory.
I don't spit the rom anymore since I need to define multiple output sections but for now it's a non issue. If there was a way to have multiple out file that would be great but I don't think the linker does that, unless mistaken. If there is one way to do it, I'm all ears ;)
The rawbin2 target will generate multiple output files if there are gaps. Otherwise, rawseg probably should work.

User avatar
Banshaku
Posts: 2393
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

Re: VBCC Optimizing C-compiler now supports NES

Post by Banshaku » Thu Jul 23, 2020 5:45 am

vbc wrote:
Wed Jul 22, 2020 3:03 am
I have created an adapted bankswitching lib from your code. When using those modifications, it should be possible to use automatic bank switching with those mappers. I would like to add this to the next release. Are there any other changes required to support those mappers?
The problem with the nes compared to other console is that there is a multitude of mapper which uses different way to bank-switch so there is no easy way to support all of them in vbcc.

To be able to do so, the code that requires the bank-switch for the far pointers needs to be available (and it is now) and either the user develop the code for the mapper he needs to interact with or he uses a few provided by vbcc as examples. That's the only way for now.

For my own mmc3 project, I may later define the code for far pointers and will check the example provided but for now my current tests do it manually and access the data like if it was in the exact same bank. It is hopefully faster than a far pointer but a little bit more fastidious since you have to do everything by hand.

User avatar
Banshaku
Posts: 2393
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

Re: VBCC Optimizing C-compiler now supports NES

Post by Banshaku » Thu Jul 23, 2020 5:52 am

vbc wrote:
Wed Jul 22, 2020 3:38 am
I have not used rawseg myself, but it does not seem to contain extra information.
Oh. If this is the case then I need to understand how segments works since I have no idea at all (laugh). If it works like I think it should that will be interesting (setting a group of sections in a segment and this segment will be exported to a file).
vbc wrote:
Wed Jul 22, 2020 3:38 am
Apparently it was specified like that in GNU ld and vlink tries to be compatible. We added RESERVE to get around the problems it causes.
I see but isn't fill the same idea as reserve somehow? what is the difference?
vbc wrote:
Wed Jul 22, 2020 3:38 am
Is there a reason for splitting the output? Do you want to do some postprocessing on the files?
Just a personal preference. An actual nes game is splitted in 2 files when written to their eeprom (if the CHR is ram then only 1 file): program data and character data. The nes header is not used on hardware but only to tell the emulator what is inside the file so my goal with my makefile is to hopefully have the 3 files generated (header, program, character) and at the end copy the 3 together to create the nes file. This way, you have a file for testing in emulator and have the files ready to write to your dev cart.

You could still use a tool to split the ending result into PRG/CHR files but if your makefile can do it, why not? So this is more a specific need and not everyone will need that.
vbc wrote:
Wed Jul 22, 2020 3:38 am
Yes, all the library code is placed into section text. Multiplication/division or floating point math will also call library functions. You can map them to your own output segments, but the library usually has to be placed into non-banked memory.
ok then. So the more I will start to use vbcc for real (now I'm just testing the linker file), the more it may add to that text segment. It is set in a non banked memory, like you mentioned, since you never know when it will need the code.
vbc wrote:
Wed Jul 22, 2020 3:38 am
The rawbin2 target will generate multiple output files if there are gaps. Otherwise, rawseg probably should work.
The rawseg it will be for my next tests. For now I'm porting some existing code so it will have to wait a little bit.

thank you again for answering my questions.

Post Reply