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

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 25, 2020 3:53 pm This warning is produced by a global optimizer pass and can not be disabled locally. You can only disable it globally.
I wouldn't want to disable it completely. It seems very useful in general. I guess I'll just leave with it. Thank you for explanations.
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 9:19 pm I wouldn't want to disable it completely. It seems very useful in general. I guess I'll just leave with it. Thank you for explanations.
If you do not mind to waste a few bytes and cycles you can prevent the warning for one loop like that:

Code: Select all

volatile const char v_one=1;
...
   while(v_one)
   {
     ...
   }
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: Wed Aug 05, 2020 11:29 pm
rox_midge wrote: Wed Aug 05, 2020 5:56 pm Does sprintf (or any other function needing vargs) not work at the moment / not work at all? It seems to copy the format string if there are no placeholders and no vargs supplied, but otherwise appears to do nothing at all.

I really don't even need sprintf, I just need a quick way to convert an int / unsigned char to a string - if there's another way (itoa, etc.), I'm glad to skip sprintf entirely.
It should work just fine. I just verified this example:

Code: Select all

#include <stdio.h>

char buf[100];

main()
{
 sprintf(buf,"test %d %c %s",123,'X',"test");
 puts(buf);
}
I've ran into something like this, too, while printing some debug strings to RAM. I've narrowed it down to using uint32_t from stdint.h. The compiler gives warning 214 suspicious format string. I've reproduced it in this example, but the effect isn't the same as it was in my program.

Code: Select all

#include <stdio.h>
#include <stdint.h>

char buf[100];

unsigned int aa = 0xAA;
unsigned short bb = 0xBB;
unsigned char cc = 0xCC;

uint32_t dd = 0xDD;
uint16_t ee = 0xEE;
uint8_t ff = 0xFF;

int main()
{
	sprintf(buf,"test %X %X %X ",aa,bb,cc);
	puts(buf);
	sprintf(buf,"test %X %X %X ",dd,ee,ff);
	puts(buf);
	sprintf(buf,"test %X %X %X %X %X %X",dd,cc,dd,dd,aa,dd);
	puts(buf);
}
In this example, the value printed after uint32_t type is always zero. If I change the type to "unsigned int", or cast it as such, the warning and the problem goes away.
vbc
Posts: 72
Joined: Sun Jun 21, 2020 5:03 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc »

Memblers wrote: Sat Aug 29, 2020 6:34 am I've ran into something like this, too, while printing some debug strings to RAM. I've narrowed it down to using uint32_t from stdint.h. The compiler gives warning 214 suspicious format string. I've reproduced it in this example, but the effect isn't the same as it was in my program.

Code: Select all

#include <stdio.h>
#include <stdint.h>

char buf[100];

unsigned int aa = 0xAA;
unsigned short bb = 0xBB;
unsigned char cc = 0xCC;

uint32_t dd = 0xDD;
uint16_t ee = 0xEE;
uint8_t ff = 0xFF;

int main()
{
	sprintf(buf,"test %X %X %X ",aa,bb,cc);
	puts(buf);
	sprintf(buf,"test %X %X %X ",dd,ee,ff);
	puts(buf);
	sprintf(buf,"test %X %X %X %X %X %X",dd,cc,dd,dd,aa,dd);
	puts(buf);
}
In this example, the value printed after uint32_t type is always zero. If I change the type to "unsigned int", or cast it as such, the warning and the problem goes away.
%X expects an int (i.e. 16 bits on 6502). If you pass a long int, you have to use %lX.
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've had the uncanny experience of "getting beaten" by this compiler. I have a function that is simple but running very often, so I tried rewriting the main part of it in asm. It turned out slower than the C version, by more than just the JSR/RTS penalty from calling the asm subroutine. The asm routine was then deleted in shame. :lol: This is with -o2, I haven't really used -o3 or above with this project yet because it makes the code too large to link.

Probably a special case because I was being lazy and leaving the more complex part in C, but it was still kinda fun to see that happen. That wasn't the case for the few other small functions I (fully) rewrote in asm.

Development has gone well with my project, I've made an arcade game emulator for NES (only playable game currently is Side Track by Exidy). It uses dynamic recompilation, but it's very slow due to lack of RAM. For now it's still using NROM, but with WRAM added at $6000-$7FFF. It's intended to eventually run on a Flash+WRAM cart, and could potentially perform better there.

There is one limitation I've found with the assembler, that it won't accept "align 256". I think it should output a warning, but still do the alignment. It helps with page-crossing penalties, but there's some things like this that can't be done without alignment. For now I suppose I can use the linker to make a segment for tables, if I need to. I haven't fully come to grips with the linker config stuff (even after going the full 15 hyperlinks deep in those GNU linker docs, haha), but the examples posted in this thread have been helpful.

I have a question about linking, I need to figure out how to specify multiple RAM segments. bss and data have been redirected to "wram" instead of "ram", but I also want to use ram. Here's what I started with:

Code: Select all

MEMORY
{
  out:     org=0x7FF0, len=0xffffff
  zero:    org=0, len=0x0100
  b0:      org=0x8000, len=0x8000
  b1:      org=0x8000, len=0x8000
  chr:     org=0x0000, len=0x2000  
  ram:     org=0x0300, len=0x0500
  wram:	   org=0x6000, len=0x2000
}

NESMAPPER    = 0 ; /* mapper number */
NESPRG_BANKS = 2 ; /* number of 16K PRG banks, change to 2 for NROM256 */
NESCHR_BANKS = 0 ; /* number of 8K CHR banks */
NESMIRRORING = 0 ; /* 0 horizontal, 1 vertical, 8 four screen */

SECTIONS
{
  header: {BYTE(0x4e);BYTE(0x45);BYTE(0x53);BYTE(0x1a);
           BYTE(NESPRG_BANKS);
           BYTE(NESCHR_BANKS);
           BYTE(NESMIRRORING|(NESMAPPER<<4));
           BYTE(NESMAPPER&0xf0);
           LONG(0);LONG(0);
          } >out

  text:   {*(text)} >b0 AT>out
  .dtors: { *(.dtors) } >b0 AT>out
  .ctors: { *(.ctors) } >b0 AT>out
  rodata: {*(rodata)}  >b0 AT>out
  init:   {*(init)}  >b0 AT>out
  data:   {*(data)} >wram AT>out

  /* fill program bank */
  fill: { .=.+0x10000-6-ADDR(init)-SIZEOF(init)-SIZEOF(data);} >b0 AT>out
  vectors:{ *(vectors)} >b0 AT>out

/*
  chars:  {
     *(chars);
     RESERVE(8192-.-ADDR(chars));
  } >chr AT>out
*/

  zpage (NOLOAD) : {*(zpage) *(zp1) *(zp2)} >zero
  bss (NOLOAD): {*(bss)} >wram

  __DS = ADDR(data);
  __DE = ADDR(data) + SIZEOF(data);
  __DC = LOADADDR(data);

  __STACK = 0x8000;

  ___heap = ADDR(bss) + SIZEOF(bss);
  ___heapend = __STACK;
}
Now I've added this line into the linker config, and trying to use it my code as such:

Code: Select all

nesram (NOLOAD): {*(nesram)} >ram

#pragma section nesram
uint8_t RAM_BASE[0x400];
#pragma section default
But it always ends up in the bss section, so I must be doing something wrong.

The compiler has been working great, only problems have been user error, haha. I did run into one strange situation with some (really ugly) code like this:

Code: Select all

cache_code[cache_index][code_index++] = (uint8_t) (((uint16_t) &cache_code[cache_index][code_index+9]) & 0xFF);
It's doing post-increment on code_index, but also using code_index+9. Whats weird is that it worked OK when this code was in main(), but it seemed like (could be a coincidence) after I moved it into a function (not recursive, and no parameters) it stopped working and my program was doing odd things. Defining a totally unrelated (and in fact, unused) variable would cause it to do different wrong behaviours, depending on the size of that reserved variable. Changing that variable into an array, the effects would go away (because then it was being placed higher in memory, after cache_code[]). The fix was simply rewriting it to only use code_index+offset, and drop the post-increment. I don't know if that's really a bug, or just a case of me writing very bad code. But it did surprise that it stopped working when I did something that I believed was unrelated. I could try to reproduce this, if this sounds like something worth looking into. (edit - note those variables and arrays are all global)

If missing optimization stuff is helpful, I could start saving cases of those. Sometimes I've seen stuff getting loaded then discarded. I'm seeing "and #255" often in the output, and that's essentially a NOP.

That Mesen label converter has been very useful.

edit:
I have a couple C/asm question. Is there a way I can JMP to a label in the C code, from assembly? At first I tried using the labels goto uses, but I think the assembly code can't see those. And conversely, maybe I can JMP from C to asm using in-line assembly, but I haven't quite figured out how to format inline asm. Is there an example of it?
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 Sep 18, 2020 10:55 am Development has gone well with my project, I've made an arcade game emulator for NES (only playable game currently is Side Track by Exidy). It uses dynamic recompilation, but it's very slow due to lack of RAM. For now it's still using NROM, but with WRAM added at $6000-$7FFF. It's intended to eventually run on a Flash+WRAM cart, and could potentially perform better there.
Nice to hear.
There is one limitation I've found with the assembler, that it won't accept "align 256".
With the oldstyle syntax module, the argument of align is the number of bits to clear. You probably want "align 8".
I have a question about linking, I need to figure out how to specify multiple RAM segments. bss and data have been redirected to "wram" instead of "ram", but I also want to use ram. Here's what I started with:

Code: Select all

MEMORY
{
  out:     org=0x7FF0, len=0xffffff
  zero:    org=0, len=0x0100
  b0:      org=0x8000, len=0x8000
  b1:      org=0x8000, len=0x8000
  chr:     org=0x0000, len=0x2000  
  ram:     org=0x0300, len=0x0500
  wram:	   org=0x6000, len=0x2000
}

NESMAPPER    = 0 ; /* mapper number */
NESPRG_BANKS = 2 ; /* number of 16K PRG banks, change to 2 for NROM256 */
NESCHR_BANKS = 0 ; /* number of 8K CHR banks */
NESMIRRORING = 0 ; /* 0 horizontal, 1 vertical, 8 four screen */

SECTIONS
{
  header: {BYTE(0x4e);BYTE(0x45);BYTE(0x53);BYTE(0x1a);
           BYTE(NESPRG_BANKS);
           BYTE(NESCHR_BANKS);
           BYTE(NESMIRRORING|(NESMAPPER<<4));
           BYTE(NESMAPPER&0xf0);
           LONG(0);LONG(0);
          } >out

  text:   {*(text)} >b0 AT>out
  .dtors: { *(.dtors) } >b0 AT>out
  .ctors: { *(.ctors) } >b0 AT>out
  rodata: {*(rodata)}  >b0 AT>out
  init:   {*(init)}  >b0 AT>out
  data:   {*(data)} >wram AT>out

  /* fill program bank */
  fill: { .=.+0x10000-6-ADDR(init)-SIZEOF(init)-SIZEOF(data);} >b0 AT>out
  vectors:{ *(vectors)} >b0 AT>out

/*
  chars:  {
     *(chars);
     RESERVE(8192-.-ADDR(chars));
  } >chr AT>out
*/

  zpage (NOLOAD) : {*(zpage) *(zp1) *(zp2)} >zero
  bss (NOLOAD): {*(bss)} >wram

  __DS = ADDR(data);
  __DE = ADDR(data) + SIZEOF(data);
  __DC = LOADADDR(data);

  __STACK = 0x8000;

  ___heap = ADDR(bss) + SIZEOF(bss);
  ___heapend = __STACK;
}
Now I've added this line into the linker config, and trying to use it my code as such:

Code: Select all

nesram (NOLOAD): {*(nesram)} >ram

#pragma section nesram
uint8_t RAM_BASE[0x400];
#pragma section default
But it always ends up in the bss section, so I must be doing something wrong.
I am not at home currently, so I cannot test it. But it looks ok. Where exactly did you put the additional linker line? Did you get any warning from the linker?
The compiler has been working great, only problems have been user error, haha. I did run into one strange situation with some (really ugly) code like this:

Code: Select all

cache_code[cache_index][code_index++] = (uint8_t) (((uint16_t) &cache_code[cache_index][code_index+9]) & 0xFF);
It's doing post-increment on code_index, but also using code_index+9.
C does not specify evaluation order. Code like this is explicitly forbidden in C and will cause undefined behaviour. Basically, if you modify an object, you must not use it anywhere else in the same statement. For the gritty details, look up on sequence points in C.
If missing optimization stuff is helpful, I could start saving cases of those. Sometimes I've seen stuff getting loaded then discarded. I'm seeing "and #255" often in the output, and that's essentially a NOP.
Optimization hints are appreciated. I will not make promises on what I can add, though.
I have a couple C/asm question. Is there a way I can JMP to a label in the C code, from assembly? At first I tried using the labels goto uses, but I think the assembly code can't see those.
No, vbcc will generate labels with numbers that are only known to the compiler.
And conversely, maybe I can JMP from C to asm using in-line assembly, but I haven't quite figured out how to format inline asm. Is there an example of it?
An example of jumping to a label or a general example of inline-assembly?

Regarding jumping to labels, you have to be very careful. vbcc will assume that inline assembly behaves similar to a function call. If the execution flow continues anywhere else, the code may not work.
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: Sat Sep 19, 2020 1:46 am
Memblers wrote: Fri Sep 18, 2020 10:55 am There is one limitation I've found with the assembler, that it won't accept "align 256".
With the oldstyle syntax module, the argument of align is the number of bits to clear. You probably want "align 8".
Good, that makes sense now. 256 bits would have been quite an alignment size, haha.

Code: Select all

#pragma section nesram
uint8_t RAM_BASE[0x400];
#pragma section default
But it always ends up in the bss section, so I must be doing something wrong.
I am not at home currently, so I cannot test it. But it looks ok. Where exactly did you put the additional linker line? Did you get any warning from the linker?
I added nesram on the line after zpage, also tried it on the line after bss, same thing in both cases. No warning from the linker. I tried adding some garbage text into the file just to make sure I was actually editing the right one, and I was.
And conversely, maybe I can JMP from C to asm using in-line assembly, but I haven't quite figured out how to format inline asm. Is there an example of it?
An example of jumping to a label or a general example of inline-assembly?

Regarding jumping to labels, you have to be very careful. vbcc will assume that inline assembly behaves similar to a function call. If the execution flow continues anywhere else, the code may not work.
Probably is too tricky to do what I was trying, basically trying to replace JSR/RTS with JMP/JMP, in a function that's only called from one place and only ever returns to one place. C code in ROM is calling an asm function in RAM, so in any case it can't just flow straight through it. It's probably not worth much effort to save those 6 cycles, though. It's called a lot, but 6 cycles is just a drop in the bucket.

But yeah a general example of inline-assembly would be useful, in case I do need it sometime.

I'll see if I can post this project up on github this week maybe. I started by having emulated ROM data in hand-made .H files, and I can't redistribute those. But now that I'm a little more comfortable with vasm and vlink, I should be able to change over to doing an .incbin. That will make it easy to drop the ROM files in, allowing the project to built by others.

On the "and #255" I'm seeing in the output, it looks like it was from me often doing stuff like 8bit_var = 16bit_var & 0xFF. Which seems to be unnecessary, after reading up on implicit type conversions, I got rid of some of the & 0xFF and explicitly cast them to 8 bits (maybe the cast isn't needed, I guess it makes it look more clear about what I'm doing). Replacing those, I saw little 2 cycle savings show up in Mesen's profiler, so that's a way to get rid of those.
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 »

Reviewing the thread, I found some inline assembly examples are here already, thanks. viewtopic.php?f=2&t=20226&start=105#p254104
vbc
Posts: 72
Joined: Sun Jun 21, 2020 5:03 pm

Re: VBCC Optimizing C-compiler now supports NES

Post by vbc »

Memblers wrote: Sun Sep 20, 2020 5:11 am

Code: Select all

#pragma section nesram
uint8_t RAM_BASE[0x400];
#pragma section default
But it always ends up in the bss section, so I must be doing something wrong.
I am not at home currently, so I cannot test it. But it looks ok. Where exactly did you put the additional linker line? Did you get any warning from the linker?
I added nesram on the line after zpage, also tried it on the line after bss, same thing in both cases. No warning from the linker. I tried adding some garbage text into the file just to make sure I was actually editing the right one, and I was.
I did a short test with your code and it seemed to work for me. Can you provide a full example?
Probably is too tricky to do what I was trying, basically trying to replace JSR/RTS with JMP/JMP, in a function that's only called from one place and only ever returns to one place. C code in ROM is calling an asm function in RAM, so in any case it can't just flow straight through it. It's probably not worth much effort to save those 6 cycles, though. It's called a lot, but 6 cycles is just a drop in the bucket.
If you do this within one asm-statement, it should be safe. Something like:

Code: Select all

  __asm("  jmp  ram_func\n"
        "return_lab:");
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: Mon Sep 21, 2020 4:00 pm I did a short test with your code and it seemed to work for me. Can you provide a full example?
I've attached it in a private message.
If you do this within one asm-statement, it should be safe. Something like:
Thanks!

--

I converted a small (600 line) asm app from ca65 to vasm, that went well. enum was the only feature lost, I had to change those to = and manually number them. That's not so bad, but there's one annoying effect after doing this, those symbol names are now in the vicemap.map, and in Mesen's debugger have taken over a lot of the variable names in zeropage. I've already seen label names like that (might be from lazynes). But it's become really noticeable after I've defined stuff as being numbered 0 thru 66. I tried using the local directive on a few of them as a test, but that didn't seem to affect this. Is there a way to avoid that? No big deal if not, it only makes things look strange in the debugger, and I suppose if I really need to, I could make a tool to strip those out of the map file.

rox_midge wrote: Mon Jul 20, 2020 5:53 am 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.
Thanks for that, I've started using it. I found a bug in byte 7, the upper 4 bits of the mapper number were misplaced.

Code: Select all

change this:
BYTE(((INES_MAPPER >> 4) & 0x0f) | ((INES_V20 & 0x01) << 3) | (INES_CONSOLE_TYPE & 0x03));

to this:
BYTE((INES_MAPPER & 0xf0) | ((INES_V20 & 0x01) << 3) | (INES_CONSOLE_TYPE & 0x03));
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 »

Memblers wrote: Fri Sep 18, 2020 10:55 am Now I've added this line into the linker config, and trying to use it my code as such:

Code: Select all

nesram (NOLOAD): {*(nesram)} >ram

#pragma section nesram
uint8_t RAM_BASE[0x400];
#pragma section default
But it always ends up in the bss section, so I must be doing something wrong.
I found the problem. RAM_BASE was defined in a C file, but was also declared extern in another H file, (which also ends up being included by that original C file). In this conflict, it appears the declared (default) section from the H file won because it's closer to the start of the source and was parsed first.
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 Sep 25, 2020 1:17 am I converted a small (600 line) asm app from ca65 to vasm, that went well. enum was the only feature lost, I had to change those to = and manually number them. That's not so bad, but there's one annoying effect after doing this, those symbol names are now in the vicemap.map, and in Mesen's debugger have taken over a lot of the variable names in zeropage. I've already seen label names like that (might be from lazynes). But it's become really noticeable after I've defined stuff as being numbered 0 thru 66. I tried using the local directive on a few of them as a test, but that didn't seem to affect this. Is there a way to avoid that? No big deal if not, it only makes things look strange in the debugger, and I suppose if I really need to, I could make a tool to strip those out of the map file.
At the moment, there is no way to filter the symbols in vasm or vlink. I could add something to filter out local symbols or absolute symbols, but I guess this is not a real solution. Either case will probably also filter out symbols that you want to keep. So you probably are better off filtering them out by yourself.

I would prefer to add real debugging information for Mesen's debugger. Its author said he would support this, but it would take a while until he finds time. Probably nothing to hold your breath yet.
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

Not too much new for NES. Mainly accumulated fixes from the last patches.

Major changes since last update:

- first version of a BBC Micro/Master target
- support for 65C02
- C99 mode is now the default, -c89 selects C89
- several bug fixes
- small code improvements
- updated/improved documentation
yaros
Posts: 47
Joined: Tue Aug 28, 2018 8:54 am

Re: VBCC Optimizing C-compiler now supports NES

Post by yaros »

I'm having a trouble (or misunderstanding) with vasm's org.
I want to reserve a space at specific address:

Code: Select all

    ; this is separate .s file. it's entire content
    section "bss"
    *=$300
__ppu_oam: reserve $100
   global __ppu_oam
Even though it places the label at $300 as requested, it overlaps with other variables in bss, as if reserve did not exist.

Code: Select all

Symbols of bss:
  0x0300 _lib_pad1: global reloc, size 0
  0x0300 __ppu_oam: global abs, size 0
  0x0301 _lib_pad1_pressed: global reloc, size 0
  0x0302 __ppu_palette: global reloc, size 0
Also org produces cryptic warning: "Warning 64: Section vbcc068f.o(seg300) was not recognized by target linker script."

Quick second question. Does vbcc care, besides inlining, if I declare C function with only __asm in body, or I just implement it in assembly .s file and link separately?
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 Oct 04, 2020 6:32 pm I'm having a trouble (or misunderstanding) with vasm's org.
I want to reserve a space at specific address:

Code: Select all

    ; this is separate .s file. it's entire content
    section "bss"
    *=$300
__ppu_oam: reserve $100
   global __ppu_oam
Even though it places the label at $300 as requested, it overlaps with other variables in bss, as if reserve did not exist.

Also org produces cryptic warning: "Warning 64: Section vbcc068f.o(seg300) was not recognized by target linker script."
You cannot have an absolute address in a non-absolute section (bss in this case). This is why vasm will create an additional section (seg300). However, the linker script does not handle this section, causing the warning and overlap.

In general, org should not be used with linkabe object files. It is useful mainly if vasm creates the final binary directly without using a linker. When using a linker, it is better to assign the memory space in the linker script. Put your area into a special section rather than bss instead of using org:

Code: Select all

    ; this is separate .s file. it's entire content
    section "myspace"
__ppu_oam: reserve $100
   global __ppu_oam
Now modify the linker file to put this section at the beginning of RAM, e.g. by changing the following line:

Code: Select all

old:  bss (NOLOAD): {*(bss)} >ram
  
new:  bss (NOLOAD): {*(myspace) *(bss)} >ram
This is assuming the default layout with ram starting at $300. If you need more fine-grained control, you can also use a separate line for your section and define separate memory regions for your section and bss.

Code: Select all

  myram:   org=0x0300, len=0x0100
  ram:     org=0x0400, len=0x0400
  ...
  myspace (NOLOAD): {*(myspace)} >myram
  bss (NOLOAD): {*(bss)} >ram
Quick second question. Does vbcc care, besides inlining, if I declare C function with only __asm in body, or I just implement it in assembly .s file and link separately?
Not really.
Post Reply