EgonOlsen71 / basicv2

A Commodore (CBM) BASIC V2 interpreter/compiler written in Java
https://egonolsen71.github.io/basicv2/
The Unlicense
84 stars 15 forks source link

Any suggestions for debugging a '?illegal quantity error in 0' error? #63

Closed gillham closed 9 months ago

gillham commented 9 months ago

This is not critical as I appear to be able to work around this by compiling with the "-xfloatopt=false" argument.

I'm testing compiling the 'Mastercode' assembler ( https://github.com/gillham/C64/tree/main/MachineCodeMaster ) with your compiler. This is a large program that uses a lot of memory. It might just be running out of memory, but hard for me to tell right now.

During the execution of the compiled binary I have it load in assembler source code from a seq file on disk. Then i tell it to assemble it. During assembly of a large file it errors out like this: ?illegal quantity error in 0 ready.

My full compile command is: ./mospeed.sh -compactlevel=3 -xfloatopt=false -target=mc.prg mastercode.bas

Do you have any suggestions for debugging this to see if it is just low on memory or some other bug? Is 'print fre(0)' going to give me a useful number for a compiled program?

Again, I seem to be working around it by disabling 'xfloatopt' which might just be freeing up enough memory to make it work. Even if it is just a low memory situation it would be nice to know a good way to tell how much memory is free at different points during execution. Thanks!

gillham commented 9 months ago

Oh and by the way... it is way faster compiled. :) I mean an assembler written in BASIC is already going to be crazy slow, but this book is from 1984. Assembling the 'mcpatch.asm' source file is 28+ minutes on VICE without warp mode or on real hardware. Meanwhile a little over 2 minutes when using the compiled version of the assembler!

EgonOlsen71 commented 9 months ago

You can use fre(0) in a compiled program as usual. It will give you the memory left for strings.

"?illegal quantity error in 0" usually happens when either there is an actual illegal quantity, which is unlikely in this situation, or if some variable gets messed up in memory and contains some illegal data. This can either be caused by the compiler's runtime going nuts (I'm not aware of any current issues with it, but you never know...), by some array access outside of the array's bounds which causes writes into some random memory location...or maybe by insufficient memory albeit I don't see why ATM...unless the array resides below the ROM and that causes the issue.

Does the BASIC version assemble the test program correctly? Have you tried using the -bigram=true option?

EgonOlsen71 commented 9 months ago

Looking at it briefly, it looks like as if -bigram=true isn't an option, because the basicloader copies the ROM into the RAM and fiddles around with it...

EgonOlsen71 commented 9 months ago

I guess you are using a modified version of mastercode.bas for compilation? Because as it is, FN DEC and FN DEEK are conflicting with each other. Even in the interpreter, one would override the other. Maybe that's not an issue, because they are never used in the same context, but it's strange anyway...

gillham commented 9 months ago

Thanks for the suggestions!

Sorry I should have mentioned. You can remove the lines from 63800 to the end. That is the checksum part that isn't needed for the compiled version of course and has the duplicate functions I believe.

If you put the compiled version on a copy of the mastercode.d64 you can load and assemble 'mcpatch.asm' which is the largest file and the one that gave me that error.

I'll do some more testing tonight after work if I can. Thanks again.

EgonOlsen71 commented 9 months ago

I see...I got it running. Doesn't look like to be memory related to me. It looks like as if something is writing into somewhere it actually shouldn't...I'll try to narrow it down...

EgonOlsen71 commented 9 months ago

Looking at the memory dump from the running application, it looks like a memory issue indeed. While loading the file, the PTR$ variable seems to extend below the ROM, which is indicated by it containing the start of the actual ROM code instead of the mapping for the lines loaded. Actually, the runtime should detect these cases and throw an OOM error, but I guess there are some edge cases where this doesn't happen.

If the loader wouldn't fiddle with the ROM by copying it into RAM, -bigram=true would solve the issue. But I'm not sure why it does this in the first place. I did all my tests directly with mastercode.bas and without the loader and I didn't see why it patches the ROM, but I guess that there has to be some reason...

gillham commented 9 months ago

Hey thanks for checking that out. Actually the 'basicloader' is used to load the BASIC extensions that are assembled. It adds a few new keywords to BASIC.

But, the assembler itself is used to assemble the extensions so isn't involved in what the basicloader is doing.

I compiled mastercode.bas with '-bigram=true' and it has 14KB free on startup. Versus just over 6KB otherwise. Nice!

It got through loading/assembling the file and generating something in memory but I will have to spend more time comparing the compilations with the BASIC version, compiled, compiled with bigram etc.

Using print fre(0) the lowest free memory I saw around 3KB with the compiled version and about 7KB with the BASIC version. I'll try with the float option enabled now also.

Ok, I ended up compiling with: ./mospeed.sh -bigram=true -target=mc.prg mastercode.bas

It is able to load/assemble 'mcpatch.asm' without any errors initially (I need to compare generated code but it looks correct). Also it took 2:10 which is slightly faster I believe than the 2:16 I was getting with compacting and the float opt off.

Thanks again Egon, I think this will work for Mastercode. I will get a cleaned up compiler friendly version in the repo and add a compiled version.

EgonOlsen71 commented 9 months ago

I called fre(0) during assembly to see how much memory is still available, but the fact that it (mostly) crashed in this phase is a red herring. The problem happens at load time. The code loaded and/or the pointer to the lines (ptr$) get corrupted because at some stage, strings are being written below the ROM, which corrupts them. Apart from increasing the memory available by using bigram (you could combine it with /compactlevel if needed and you might want to consider to limit the additional RAM to $C000 by doing /varend=49152 to be able to still assemble stuff into the 4K from $C000 to $D000), it might be possible to reduce memory usage at load time. I haven't checked, what exactly it's doing there, but it might be possible to "null" some strings (by setting them to "") early there to help the garbage collector to free up more memory.