Limit in total code size? [SOLVED]

Discussion of hardware and software development for Super NES and Super Famicom. See the SNESdev wiki for more information.

Moderator: Moderators

Forum rules
  • For making cartridges of your Super NES games, see Reproduction.
drludos
Posts: 62
Joined: Mon Dec 11, 2017 4:01 pm

Limit in total code size? [SOLVED]

Post by drludos »

I'm still (slowly) working on my SNES game project with PVSNESLib (so C code with tcc816 + Wlalink backend).

I know that this toolset has many quirks and limitations, but I've encountered a strange behavior that maybe some of you have dealed with:
Is there some kind of "limit" in the overall code size for the game? (at least for this toolset)

I'm starting to have a quite large game (about 2000 lines in C code, if you exclude comments and PVSNESlib components, in a single c file.). After adding a large function, the code randomly crashes the console. To be more specific, it seems to crash the SPC700, which crashes the console whenever it doesn't like the code or data you sent to it.

At first, I thought it was another case of the "no more than 32k of code in a single function" problem, that I've already encountered earlier in the project. So I again moved some code away from my "main" function, with various results: some time it still crashes, some time it work but the sound streaming functions have problems (sound is glitched).

However, when I comment out large chunk of code in the new functions I created (or in another function called by the main loop), it all goes back to normal.

I've tried to expand the total ROM size, to modify the bank of the sound data, etc. - nothing makes it work with all the code in :(.

My theory is that the total code is simply "too large" for tcc-816, and it can't process it for some reason, whether it's inside a function or not. And I guess that the code that is "left out" by the compiler, is unfortunately the "SPC driver" from the lib (SNESmod), making the SPC700 crash whenever I trigger a sound play.

Did anything similar ever happened to you?

If yes, is there some kind of workaround for this issue (splitting the code in several .c files? etc.)

Before posting here, I've also contacted Shiru, who has a lot of experience with this toolset. He thinks that there isn't any "total code limit", but that it's related to the lack of reliance of the tools (code can't stop working due to a misalignement of compiled code).

EDIT: this is issue is solved (look at the last post) - it was a bug when the code of the SNESmod lib isn't stored in bank 0.
Last edited by drludos on Tue Feb 06, 2018 2:33 pm, edited 2 times in total.
Download ROMs of my games: https://drludos.itch.io/
Support my work and get access to beta and prototypes: https://www.patreon.com/drludos
Optiroc
Posts: 129
Joined: Thu Feb 07, 2013 1:15 am
Location: Sweden

Re: Limit in total code size?

Post by Optiroc »

Have you tried investigating the bug with a debugging emulator? Neither tcc nor wla is super reliable, so there’s really no better way to learn more than trying to pinpoint the issue in a debugger.
User avatar
HihiDanni
Posts: 186
Joined: Tue Apr 05, 2016 5:25 pm

Re: Limit in total code size?

Post by HihiDanni »

I would try to run the game in Benny's fork of bsnes-plus: https://forums.nesdev.com/viewtopic.php?f=12&t=16625

There's an option to break execution on the BRK opcode. Turn it on and then hard reset. If it hits a BRK (i.e. executes a 0 byte), you'll know there's something wrong with the code that was generated.
SNES NTSC 2/1/3 1CHIP | serial number UN318588627
drludos
Posts: 62
Joined: Mon Dec 11, 2017 4:01 pm

Re: Limit in total code size?

Post by drludos »

Hi, thanks for your replies.

I must confess I'm a total noob regarding ASM (although I start to get a few glimpse of it after using it to declare resources in PVSNESLib, or when I had issues with SNESmod).

Is BSNES debugger available in compiled form (windows) somewhere?

In the meantime, I tried to do this manipulation with NoSNS:

I've made several different builds (crashing, non-crashing, etc.), and when the game was crashed (or rather "stuck"), I looked at the lines in the NoSNS debugger. By using "animate", I noticed that two cursor is jumping between two lines when the game is stuck:
crashing code (but sound glitch):

Code: Select all

0001:FAAB EC 40 21 cmp x,[2140]
0001:FAAE D0 FB jnz FAA7
(I have no clue about what those line are doing - is it some kind of "while (x == 2140){ }")

If I remove some code elsewhere, I can have a non-crashing build, but with sound glitch. The same code as above is present, but in different lines:

Code: Select all

0001:FAA7 EC 40 21 cmp x,[2140]
0001:FAAA D0 FB jnz FAA7
And, last but not least, whenever I remove the last function I programmed entirely, it reverses the game to a "no crash / no glitch" state. The two lines above aren't present (using "Search" I can't find them, and they are not located around the 0001:FAAA space - I've searched them manually)

So could it be a simpler case of badly produced code in the last function I wrote, which will make the game crash / glitch only if there as at least XXX lines of codes in the total program?

It seems very strange to me, because if I keep this last function, but I remove another one, the games run great (no glitch no crash). So it's the addition of my previous code + the new one that doesn't please the compiler. At least it would match the "broken toolchain" theory (both Shiru and you seem to agree on this point).

If that's the case, what would be the best way to fix it?

Do I simply try to rewrite my function in a different way so the compiled code is different?

Or are there known workaround / guideline to try to avoid such compiler quirks?

Thanks again a lot for your help!
Download ROMs of my games: https://drludos.itch.io/
Support my work and get access to beta and prototypes: https://www.patreon.com/drludos
drludos
Posts: 62
Joined: Mon Dec 11, 2017 4:01 pm

Re: Limit in total code size?

Post by drludos »

Well, after some additional testing, I've got a new lead: I definitively think it's related to the total code size!

I've removed the last function I put in, and I've tried to increase the total code size by copy-pasting some code from older (previously working) functions.

I doesn't crash the game per se, but, when I add enough code, the game refuses to compile.
wla-65816 is throwing me the following error:

Code: Select all

Game.asm:INPUT_NUMBER: Out of 16bit range.
Game.asm:20: ERROR: Couldn't parse "sbc".
Does it mean that I have too much code?
(All my game is stored in a single C file, about 2000 lines if you don't count the comments)
Download ROMs of my games: https://drludos.itch.io/
Support my work and get access to beta and prototypes: https://www.patreon.com/drludos
User avatar
Khaz
Posts: 314
Joined: Thu Dec 25, 2014 10:26 pm
Location: Canada

Re: Limit in total code size?

Post by Khaz »

Could you maybe find that line 20 in the Game.asm file that's throwing the error and copy it? "Out of 16 bit range" iirc is an error when the operand is not a valid number to subtract, eg/ larger than a 16 bit number...

I'm pretty fluent in the ASM but not the tools you're using. I know WLA has some quirks with operand sizes and maybe you've found a specific case where the C library didn't account for that?

The bit you posted, "cmp x,[2140], jnz FAA7" is an infinite loop because the branch condition (jump if not zero) is always met following the compare instruction. I'm not sure what it's comparing to so I can't really say why. The part that makes me suspicious is how it's always jumping to FAA7, even when changes you've made have relocated that bit of code from FAAB to FAA7. Maybe it's interpreting that branch instruction wrong?

Lot of theories, hard to say without more information but maybe something I've said will be helpful?
User avatar
Khaz
Posts: 314
Joined: Thu Dec 25, 2014 10:26 pm
Location: Canada

Re: Limit in total code size?

Post by Khaz »

Actually! I think I understand the last error.

I think it's saying "out of 16 bit range" because it's trying to subtract a value stored in an address that is too far away to read with that sbc instruction. I believe if it's "out of 16 bit range" that means that it's trying to read from another bank. This fits your "too much code" theory in the sense that too much code will spill over into another bank, which might screw with parts of code trying to read data from across banks. You still have plenty of ROM space (I'd wager) but you might need to break things up into more manageable pieces so each one fits in a single bank.
Optiroc
Posts: 129
Joined: Thu Feb 07, 2013 1:15 am
Location: Sweden

Re: Limit in total code size?

Post by Optiroc »

It seems SMP related, so your guess about that was correct. The 65816 is waiting for the sound CPU to put #0 on IO port 0, which never happens.
drludos
Posts: 62
Joined: Mon Dec 11, 2017 4:01 pm

Re: Limit in total code size?

Post by drludos »

Woaw, thanks a lot for your reply (and your expertise)!

The instruction that output the error (in line 20) is:

Code: Select all

sbc #__init_locals
For some context, here are the first 30 lines of the ASM code (generated by tcc816 + WLA from my C source):
(The "hdr.asm" file is the header of the rom, manually defined in asm format in PVSNESlib.)

Code: Select all

.include "hdr.asm"
.accu 16
.index 16
.16bit
.define __init_locals 1406074
.define __startGame_locals 1407734
.define __main_locals 1406610
.define __spawnFoe_locals 1407259
.define __setWave_locals 1407221
.define __spawnBonus_locals 1407690
.define __spawnBoom_locals 1408129
.define __updateTitle_locals 1409797
.define __updateIntro_locals 1408667
.define __updateEnding_locals 0
__local_1004:
.section ".text_0x0" superfree
init:
.ifgr __init_locals 0
tsa
sec
sbc #__init_locals
tas
.endif
jsr.l spcBoot
jsr.l consoleInit
sep #$20
lda #0
pha
rep #$20
jsr.l setBrightness
I think you are indeed right. By reading the ".sym" file generated by the tools, it seems that the SPC related functions of my code are located at the end of the file. So it's logical that, if the code "overflows" from a single 32k rom bank, they are the ones that miss instructions and crash the console. This is a very useful lead, thanks a lot!
Khaz wrote:Actually! I think I understand the last error.

I think it's saying "out of 16 bit range" because it's trying to subtract a value stored in an address that is too far away to read with that sbc instruction. I believe if it's "out of 16 bit range" that means that it's trying to read from another bank. This fits your "too much code" theory in the sense that too much code will spill over into another bank, which might screw with parts of code trying to read data from across banks. You still have plenty of ROM space (I'd wager) but you might need to break things up into more manageable pieces so each one fits in a single bank.
I do have several empty ROM banks, but how can I "break things up into more manageable pieces"?

From the beginning of the project, I've already split my code is several functions (although all of them are in a single .c file), thinking that it would help the compiler / linker to split the code over several banks. But it doesn't seem to work as I now have this issue.

How can I allow the compiler to split my code over several banks?
(by splitting in several .c files maybe?)

Thanks again a lot for your help!
Download ROMs of my games: https://drludos.itch.io/
Support my work and get access to beta and prototypes: https://www.patreon.com/drludos
calima
Posts: 1745
Joined: Tue Oct 06, 2015 10:16 am

Re: Limit in total code size?

Post by calima »

Neither the compiler nor the assembler has automatic banking, AFAIK you have to do it manually.
drludos
Posts: 62
Joined: Mon Dec 11, 2017 4:01 pm

Re: Limit in total code size?

Post by drludos »

Hi, thanks a lot for the info - if the compiler/assembler can't automatically split code into banks, that explains everything!

Now, a last question remains: how we can split the code into banks using this toolset?

I know that you have to declare manually where to "store" graphics and sound data (using a file called data.asm), such as:

Code: Select all

.include "hdr.asm"

; BANK0 (32ko) : Graphics

.section ".rodata1" superfree
spritesGFX:
.incbin "player.pic"
.incbin "foe.pic"
spritesGFX_end:

spritesPAL:
.incbin "player.pal"
.incbin "player2.pal"
.incbin "foe.pal"
spritesPAL_end:

.ends


; BANK1 (32ko) : Sounds
.section ".rodata2" superfree

shootSFX: 
.incbin "sfx_shoot.brr"
shootSFX_end:

hitSFX: 
.incbin "sfx_hit.brr"
hitSFX_end:

bonusSFX: 
.incbin "sfx_bonus.brr"
bonusSFX_end:

.ends
There is also an additional soundbank.asm file looking like this one to split the music tracks into banks. But there is no mention of where the code is stored in either of those files.

So, do you know how to declare in which ROM banks the code will be stored?

Thanks again for your help!
Download ROMs of my games: https://drludos.itch.io/
Support my work and get access to beta and prototypes: https://www.patreon.com/drludos
drludos
Posts: 62
Joined: Mon Dec 11, 2017 4:01 pm

Re: Limit in total code size?

Post by drludos »

Some additional info I think I understand after reading the wla.txt help file.

Each time you create a new function in your c source file, it'll be generated in it's own ".section superfree". So I guess that splitting your code in many functions should help the compiler / assembler to produce smaller "pieces".

And I've tried just that, and now the resulting asm file has many more ".section "uniquelabel" superfree" in it, each section corresponding to one function I wrote in the c source file.

However, for now it doesn't solve my issue: the game keeps on crashing / freezing.

So I guess that "splitting" the code in smaller ".section superfree" isn't enough to allow the linker to split the code over several banks.

Thanks again for your help, because learning SNESDev ain't easy :)!
Download ROMs of my games: https://drludos.itch.io/
Support my work and get access to beta and prototypes: https://www.patreon.com/drludos
drludos
Posts: 62
Joined: Mon Dec 11, 2017 4:01 pm

Re: Limit in total code size?

Post by drludos »

So, it happens that my code was already split over several banks. Indeed, the tcc816 compiler wraps each C function inside a dedicated ".section" with the superfree status. So, when WLA-DX process the ASM code generated by tcc816, it automatically store the code inside the rom banks using its own algorithm (larger .sections first).

After long hours of testing, I've finally managed to pinpoint the source of my problem. It wasn't a "code overflow" as I suspected, but it was indeed related to the organization of the code in the rom.

It seems that the SNESmod library doesn't like to be stored in a rombank other than 0.
When the SNESmod related functions are stored in Rombank 1 or 2, the streaming function of the library crashes (or, more specifically, are stuck in an endless loop). The problem is that, in PVSNESlib, the SNESmod related function are declared in ".section superfree" too.

On my case, when I created larger functions in the code of my game, WLA automatically stored these functions in a rom bank located before the ones related to SNESmod, thus crashing the library.

To slove this, for now I'm manually editing the ASM file generated by tcc816 in order to force some of my code to be stored in banks 1, 2 and 3, leaving room in bank 0 for the superfree sections like the ones related to SNESmod. Once I got this process working, I even made a small python script to automatically perform this modification in the ASM source.

So, for now, I can finally resume working on my game - I can't describe how happy I am that this issue is finally solved! :)

Thanks again to all of you for your tips and answers - I could never have figured out this all by myself (once again!)
Download ROMs of my games: https://drludos.itch.io/
Support my work and get access to beta and prototypes: https://www.patreon.com/drludos
KungFuFurby
Posts: 275
Joined: Wed Jul 09, 2008 8:46 pm

Re: Limit in total code size? [SOLVED]

Post by KungFuFurby »

I have found the offending line regarding the streaming portion crashing, now that I know the answer.

At line 1073 (going by the latest version of pvSNESLib...)

Code: Select all

lda digi_rates.w, x
Modify this line to...

Code: Select all

lda.l digi_rates, x
(or maybe this one could work...)

Code: Select all

lda digi_rates.l, x
This happened due to the data bank register being set to zero, which causes invalid parameters to be loaded to digi_rates.
drludos
Posts: 62
Joined: Mon Dec 11, 2017 4:01 pm

Re: Limit in total code size? [SOLVED]

Post by drludos »

Woaw, thanks (again!) a lot for your help KungFuFurby - you really are the SNESmod expert!

I'm forwarding your modifications to Alekmaul, the creator of PVSNESlib, so he can include them in the codebase, thus solving the issue for everyone :)
Download ROMs of my games: https://drludos.itch.io/
Support my work and get access to beta and prototypes: https://www.patreon.com/drludos
Post Reply