A strange behavior of the code - what is wrong? [solved]
pik33
Posts: 2,366
I am trying to get .sid file header.
This code works wrong:
dim speed, r as ulong dim version, offset, load, startsong, flags, init, play, songs, song as ushort dim il,b as ubyte dim ititle,iauthor,icopyright as ubyte(32) dim atitle,author,copyright as string dim i as integer mount "/sd", _vfs_open_sdcard() chdir "/sd/sid/selected" let filename3$="/sd/sid/selected/bilinski.sid" close #8: open filename3$ for input as #8 atitle=""'" " author=""'" " copyright=""'" " get #8,5,version,2,r : version=((version and 255) shl 8) or (version shr 8) : print version get #8,7,offset,2,r : offset=(offset shl 8) or (offset shr 8) get #8,9,load,2,r : load=(load shl 8) or (load shr 8) get #8,11,init,2,r : init=(init shl 8) or (init shr 8) get #8,13,play,2,r : play=(play shl 8) or (play shr 8) get #8,15,songs,2,r : songs=(songs shl 8) or (songs shr 8) get #8,17,startsong,2,r : startsong=(startsong shl 8) or (startsong shr 8) get #8,19,speed,4,r speed=speed shr 24+((speed shr 8) and $0000FF00) + ((speed shl 8) and $00FF0000) + (speed shl 24) get #8,23,ititle(0),32,r get #8,55,iauthor(0),32,r get #8,87,icopyright(0),32,r if version>1 then get #8,119,flags,2,r : flags=(flags shl 8) or (flags shr 8) b=0 : if load=0 then b=1 : get #8,125,load,2,r endif for i=0 to 31 : atitle=atitle+chr$(ititle(i)): next i for i=0 to 31 : author=author+chr$(iauthor(i)) : next i for i=0 to 31 : copyright=copyright+chr$(iauthor(i)) : next i print ("version: "): print(hex$(version,4)) print ("offset: "): print(hex$(offset,4)) print ("load: "): print(hex$(load,4)) '178-144*b); print ("init: "): print(hex$(init,4)) print ("play: "): print(hex$(play,4)) print ("songs: "): print(hex$(songs)) print ("startsong: "): print(hex$(startsong)) print ("speed: "): print(hex$(speed,8)) print ("title: "): print(atitle) print ("author: "): print(author) print ("copyright: "): print(copyright) print ("flags: "): print(hex$(flags,4))
The result:
2 version: 736E offset: 696B load: 1000 init: 0000 play: 1003 songs: 1 startsong: F24C speed: 00000001 title: Bilinski author: Wojciech Radziejewski (Shogoon) copyright: Wojciech Radziejewski (Shogoon) flags: 0024
"2" written first is the proper version number. However somewhere later it got garbled, and $736e is garbage, The offset, $696b is aiso garbage, while the rest of fields are correct.
However, this code works as expected:
dim version, offset, load, startsong, flags, init, play, songs, song as ushort dim il,b as ubyte dim ititle,iauthor,icopyright as ubyte(32) dim atitle,author,copyright as string dim i as integer dim speed, r as ulong (... the rest is exactly the same)
The only change is the declaration of speed and r moved from the first line of the code to the last line of the declaration block
The result is now correct:
2 version: 0002 offset: 007C load: 1000 init: 0000 play: 1003 songs: 1 startsong: F24C speed: 00000001 title: Bilinski author: Wojciech Radziejewski (Shogoon) copyright: Wojciech Radziejewski (Shogoon) flags: 0024
What can be wrong here?
The compiler version and parameters:
"/home/pik33/Programy/flexprop/bin/flexspin" -2 -l --tabs=8 -D_BAUD=230400 -O1 --charset=utf8 -I "/home/pik33/Programy/flexprop/include" "/home/pik33/Programowanie/P2-retromachine/Propeller/Tracker player psram 2/sidtest.bas" -DFF_USE_LFN Propeller Spin/PASM Compiler 'FlexSpin' (c) 2011-2022 Total Spectrum Software Inc. Version 5.9.10-beta-v5.9.9-93-ge37a63f5 Compiled on: Apr 3 2022
Comments
Try diff-ing the generated assembly between the two cases. That will lead to more insight.
Also, there have been a few bug fixes since your version, so try re-building I guess
Too many differences between the .lst files. Then, I started to comment out instructions to find what causes the "version" variable to change.
get #8,19,speed,4,r
Commenting it out makes "version" to be unchanged.
I will try to recompile the the new compiler and try if it is different there. As a workaround in the player, where this error is also present (and from where I extracted the test code) I will simply get the entire header and extract fields out of it.
Edit: recompiled, nothing changed.
I thought file handles had to be between 0 and 7 in FlexBASIC. Is the “8” freaking it out?
I tested #7, it works exactly the same way. Also I tried to declare several dummy variables between used ones. The result changes depending on how many variables I add, but is still incorrect.
The player gets a lot of data from files, file handles up to #9 works OK, all file transfers worked as expected before.
This is the simplest version of bad working code.
The result:
512 is what it should be.
Changing declaration order makes the program work.
Hmm, did a quick check, it's not a codegen issue AFAICT. This is the entire difference, as it should be:
So I guess something goes wrong in
__system___basic_get
? IRDK...Yes, I already compared listings of this simple code. It was simple enough to check - there seems to be nothing wrong in the main program compiled code. It seems as it is __system__basic_get which does something wrong
If "speed" is declared after "version", all is OK. If it is declared before, "version" is overwritten as if "get" gets more than 4 bytes and overwrites next variables with what it gets.
In the long "full" version of sid reader, these "bad" values in "version" (and "offset") are not random. They are read from the file at one of these strings location. I will check what exact file position they are from.
Edit:
In the simple program from post #6, "version" is declared after "speed" and get before "speed", "version" is overwritten with these 2 bytes which are in the file directly after the "speed"
Solved.
The amount field in "get" is not a byte count to load. It is amount of bytes*sizeof(variable) to which it loads.
When I tell it to get #7, speed, 4 it got 4*sizeof(ulong) which is 16 bytes, overwriting the variables which was declared after.
Wow, as a passive observer, this stumped me too:
GET as described in /doc/basic.md:
get #handle, pos, var [,items [,r]]
get is used to read binary data from the open file whose handle is handle, starting at position pos in the file (where pos is 1-based).
Several important caveats apply:
(1) The bytes are read as binary data, not ASCII.
(2) Strings may not be read in this way. The compiler will not throw an error for using a string type, but what is read is the 4 byte pointer for the string, not the string data itself.
(3) The return value r is "items read" rather than "bytes read" as it is in FreeBasic.
(4) If an error occurs, r is set to -1.
I have a Pascal background: "get" is equivalent of Pascal's fileread (handle, variable, amount). Pascal's amount is bytes, so fileread handle,variable,sizeof(variable)) and that's why I didn't see the error so long.
What helped to find the error in the code was the last test I did: I declared a lot of variables, "get" the first of it, printed all of them. It gets 16 bytes... Voila - then I opened the manual and read the text you put above.
This position numbered from 1 instead of 0 is the second quirk of Basic's get command, but forgetting about this gives an instant error.
There is a lot to relearn and remember, but from these 3 languages available for P2 in Flexprop compiler, Basic is the easiest to use for a Pascal programmer with (Atari) Basic background from 35 years ago. Maybe I will have to do something also in C, there are still things I cannot do in Basic and the file system. For example, delete the file.
It's a classic, never-ending hazard in C. BASIC normally protects you from it though.