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.
VBCC Optimizing C-compiler now supports NES
Moderator: Moderators
Re: VBCC Optimizing C-compiler now supports NES
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)
{
...
}
Re: VBCC Optimizing C-compiler now supports NES
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.vbc wrote: ↑Wed Aug 05, 2020 11:29 pmIt should work just fine. I just verified this example: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.Code: Select all
#include <stdio.h> char buf[100]; main() { sprintf(buf,"test %d %c %s",123,'X',"test"); puts(buf); }
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);
}
Re: VBCC Optimizing C-compiler now supports NES
%X expects an int (i.e. 16 bits on 6502). If you pass a long int, you have to use %lX.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.
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.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); }
Re: VBCC Optimizing C-compiler now supports NES
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. 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:
Now I've added this line into the linker config, and trying to use it my code as such:
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:
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?
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;
}
Code: Select all
nesram (NOLOAD): {*(nesram)} >ram
#pragma section nesram
uint8_t RAM_BASE[0x400];
#pragma section default
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);
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?
Re: VBCC Optimizing C-compiler now supports NES
Nice to hear.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.
With the oldstyle syntax module, the argument of align is the number of bits to clear. You probably want "align 8".There is one limitation I've found with the assembler, that it won't accept "align 256".
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 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:Now I've added this line into the linker config, and trying to use it my code as such: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; }
But it always ends up in the bss section, so I must be doing something wrong.Code: Select all
nesram (NOLOAD): {*(nesram)} >ram #pragma section nesram uint8_t RAM_BASE[0x400]; #pragma section default
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.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:It's doing post-increment on code_index, but also using code_index+9.Code: Select all
cache_code[cache_index][code_index++] = (uint8_t) (((uint16_t) &cache_code[cache_index][code_index+9]) & 0xFF);
Optimization hints are appreciated. I will not make promises on what I can add, though.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.
No, vbcc will generate labels with numbers that are only known to the compiler.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.
An example of jumping to a label or a general example of inline-assembly?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?
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.
Re: VBCC Optimizing C-compiler now supports NES
Good, that makes sense now. 256 bits would have been quite an alignment size, haha.
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 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?But it always ends up in the bss section, so I must be doing something wrong.Code: Select all
#pragma section nesram uint8_t RAM_BASE[0x400]; #pragma section default
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.An example of jumping to a label or a general example of inline-assembly?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?
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.
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.
Re: VBCC Optimizing C-compiler now supports NES
Reviewing the thread, I found some inline assembly examples are here already, thanks. viewtopic.php?f=2&t=20226&start=105#p254104
Re: VBCC Optimizing C-compiler now supports NES
I did a short test with your code and it seemed to work for me. Can you provide a full example?Memblers wrote: ↑Sun Sep 20, 2020 5:11 amI 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 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?But it always ends up in the bss section, so I must be doing something wrong.Code: Select all
#pragma section nesram uint8_t RAM_BASE[0x400]; #pragma section default
If you do this within one asm-statement, it should be safe. Something like: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.
Code: Select all
__asm(" jmp ram_func\n"
"return_lab:");
Re: VBCC Optimizing C-compiler now supports NES
I've attached it in a private message.
Thanks!If you do this within one asm-statement, it should be safe. Something like:
--
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.
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.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.
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));
Re: VBCC Optimizing C-compiler now supports NES
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.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:But it always ends up in the bss section, so I must be doing something wrong.Code: Select all
nesram (NOLOAD): {*(nesram)} >ram #pragma section nesram uint8_t RAM_BASE[0x400]; #pragma section default
Re: VBCC Optimizing C-compiler now supports NES
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.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.
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.
Re: VBCC Optimizing C-compiler now supports NES
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
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
Re: VBCC Optimizing C-compiler now supports NES
I'm having a trouble (or misunderstanding) with vasm's org.
I want to reserve a space at specific address:
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."
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?
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
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
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?
Re: VBCC Optimizing C-compiler now supports NES
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.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:
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
; this is separate .s file. it's entire content section "bss" *=$300 __ppu_oam: reserve $100 global __ppu_oam
Also org produces cryptic warning: "Warning 64: Section vbcc068f.o(seg300) was not recognized by target linker script."
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
Code: Select all
old: bss (NOLOAD): {*(bss)} >ram
new: bss (NOLOAD): {*(myspace) *(bss)} >ram
Code: Select all
myram: org=0x0300, len=0x0100
ram: org=0x0400, len=0x0400
...
myspace (NOLOAD): {*(myspace)} >myram
bss (NOLOAD): {*(bss)} >ram
Not really.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?