I've actually run into similar weirdness as well, and quite frankly, I can't even debug the problem, I had to put the project I was working on hold until some future date when I better understand the weirdness that is the C64 dos and it's adaptation into SDcard storage.
The operative phrase here in Ed's post was "I wrote some code to save a file with the following filename: "
I.E. He wrote some code, not typed commands into the BASIC prompt. Don't forget that originally, everything was "floppy disk sized" and directories weren't a thing.
Sure, typing commands into the BASIC prompt actually works. But the interface to do that with code is painfully undocumented.
Switching to R43 frustration
-
- Posts: 503
- Joined: Sat Jul 11, 2020 3:30 pm
Re: Switching to R43 frustration
To be clear, I'm doing all of this in assembly language.
Also, I have no trouble loading files in the DEMO folder; tilemaps and palettes and other files load just fine, no colon characters involved. It is only files in a subfolder such as IMG that I can't load, though I can save there (again, with a filename with no colons in it).
Re: Switching to R43 frustration
Maybe post the code in question? As far as I understand, BASIC is mostly just doing some kernal calls so it being assembly shouldn't matter much. I also tried adding another level of subfolders to my test and it didn't make a difference.Ed Minchau wrote: ↑Fri Jul 14, 2023 3:12 amTo be clear, I'm doing all of this in assembly language.
Also, I have no trouble loading files in the DEMO folder; tilemaps and palettes and other files load just fine, no colon characters involved. It is only files in a subfolder such as IMG that I can't load, though I can save there (again, with a filename with no colons in it).
Re: Switching to R43 frustration
Ok, that starts to look helpful.DragWx wrote: ↑Fri Jul 14, 2023 12:41 am I did a quick look at the kernal rom, and the parser wants something like this:
"@0/HERES/MY/PATH/:FILE.PRG"
I think you can omit the leading number (it's the "medium" and it defaults to zero). The path part must begin and end with a slash, and the part directly after the colon is the filename plus options like usual.
I can't test right now to confirm, sorry.
Is that format always using an absolute path? I've had problems after I used the command channel to set a path, then attempted to load a file assuming the kernal knows where the "current path is." I assume the system has some concept as to what it's "current path" is... my only way to get that is to get a dir and use only the path.
My only documentation for this is the original C64 docs, and is impressively obtuse... I want to ask it questions like "What does the secondary channel do when it's a read or write? Does it's modulus of evenness in the range of 0 to 14 determine the logical channel within the specified device?"
It LOOKS, like from what you just posted, that the filename given to FILNAM is now a literal, absolute path with a large number of characters.
But... "and the part directly after the colon is the filename plus options like usual." implies that the @ (For replace?) should be after the : in the path. Or are there options that go AFTER the : and some that go before?
Re: Switching to R43 frustration
If you want to enable overwriting, the '@' always goes as the first character of the string, and must be somewhere before a ':'. So for example, "@FILE.PRG" is incorrect, "@:FILE.PRG" is what you want, "@0/PATH/:DATA.BIN" if you also want a path.
The options I mentioned were the ones after the filename, like "FILE.PRG,S,W".
Additionally, there is a difference between absolute and relative paths:
"@0/MY/RELATIVE/PATH/:FILE.PRG"
"@0//MY/ABSOLUTE/PATH/:FILE.PRG"
It's the addition of one extra slash, yes.
I'd assume relative paths are relative to whatever directory you last explicitly changed to, i.e., with DOS commands, and that loading and running a program won't automatically set DOS's working directory to be the directory the program is in (like if you loaded the program via absolute path instead of switching into that directory and loading by just filename).
The internal buffer for parsing the filename string into a path, filename, options, etc is 256 characters, but I haven't checked if there are different size limits in the other routines for actually passing this string to commander dos; I only looked at the parser code.
The options I mentioned were the ones after the filename, like "FILE.PRG,S,W".
Additionally, there is a difference between absolute and relative paths:
"@0/MY/RELATIVE/PATH/:FILE.PRG"
"@0//MY/ABSOLUTE/PATH/:FILE.PRG"
It's the addition of one extra slash, yes.
I'd assume relative paths are relative to whatever directory you last explicitly changed to, i.e., with DOS commands, and that loading and running a program won't automatically set DOS's working directory to be the directory the program is in (like if you loaded the program via absolute path instead of switching into that directory and loading by just filename).
The internal buffer for parsing the filename string into a path, filename, options, etc is 256 characters, but I haven't checked if there are different size limits in the other routines for actually passing this string to commander dos; I only looked at the parser code.
Re: Switching to R43 frustration
Ok. This is starting to make sense. The reason what I was working on was failing when using an absolute path after telling the system to change to a sub directory was because it misinterpreted my path, "/absolute/path/to_this_file" as a relative path. The correct absolute path would be: "@0//absolute/path/:to_this_file" where the "@", the "0" and the final ":" are essentially optional. (I'm sure there are situations where the ":" is required, and it should be included as rote.)
I expect that if no path at all is provided, then the ":" is required if there are leading options, like the "@", like "@:my_file" and if you were reading (No need for an overwrite flag.) it could be shortened to ":my_file" or even "my_file"
But for reasons of clarity, the "@", ":", and full relative (If one exists.) or absolute path should be included.
I expect that if no path at all is provided, then the ":" is required if there are leading options, like the "@", like "@:my_file" and if you were reading (No need for an overwrite flag.) it could be shortened to ":my_file" or even "my_file"
But for reasons of clarity, the "@", ":", and full relative (If one exists.) or absolute path should be included.
-
- Posts: 503
- Joined: Sat Jul 11, 2020 3:30 pm
Re: Switching to R43 frustration
I found my error. I sent an incorrect parameter to the LOAD function. The filename didn't need a colon in it at all, except the @: prepended to it for an overwriting save.
The x16 programmer's reference guide lists the CMD subdirectory syntax as
Just using the plain DIR/SUBDIR/PROGRAM.PRG syntax works fine in the emulator; we really should just keep it simple and leave it that way.
The x16 programmer's reference guide lists the CMD subdirectory syntax as
Code: Select all
//DIR/://DIR/:
Re: Switching to R43 frustration
As long as we're here...
Also from the CMD dos manual:
Example
OPEN 1,8,2,"LEVEL.DAT,S,R"
OPEN 15,8,15,"P"+CHR$(2)+CHR$(0)+CHR$(1)+CHR$(0)+CHR$(0)
This opens LEVEL.DAT for reading and positions the read/write pointer at byte 256.
OPEN 2,8,5,"LEVEL.DAT,S,R"
OPEN 15,8,15,"P"+CHR$(5)+CHR$(128)+CHR$(0)+CHR$(0)+CHR$(0)
This time, the secondary address is 5, and the pointer is at byte 128.
Here's what confuses me the most: Aren't the BASIC OPEN command's first 3 params (E.G: "1,8,2") The same as the parameters for the KERNAL call "SETLFS"?
I get that putting 15 in the secondary address accesses the command mode, but why is it ALSO in the FA param? Doesn't the FA param reference a table of open files? They're the same file in examples 1 and 2... If you need a unique id for each concurrent action, wouldn't you just use the FA indexes in order?
Then in example 2 and 3, 5 is used as the SA for the first call... wait! Isn't 5 odd? Doesn't that mean a write operation? For that matter, how does the second OPEN (example 4) know about the 5? And why isn't it 2 like in the first example? or 4?
I feel like a priest is telling me how to invoke a magic ritual by chanting it's unknowable name. Obviously, that's not the actual case... computers are completely deterministic and will do exactly what you tell them to. I get that some of these magic numbers might mean something to some arcane interface you might see on the serial bus that C64 drives used to be connected to, but 99.9% of the time I would think the SDcard is what's being used.
I don't WANT to have PhD level knowledge of the C64's dos or it's kernal calls. I just want to know how the few calls I actually need to use work with the SDcard.
Sorry for the rant.
Also from the CMD dos manual:
Example
OPEN 1,8,2,"LEVEL.DAT,S,R"
OPEN 15,8,15,"P"+CHR$(2)+CHR$(0)+CHR$(1)+CHR$(0)+CHR$(0)
This opens LEVEL.DAT for reading and positions the read/write pointer at byte 256.
OPEN 2,8,5,"LEVEL.DAT,S,R"
OPEN 15,8,15,"P"+CHR$(5)+CHR$(128)+CHR$(0)+CHR$(0)+CHR$(0)
This time, the secondary address is 5, and the pointer is at byte 128.
Here's what confuses me the most: Aren't the BASIC OPEN command's first 3 params (E.G: "1,8,2") The same as the parameters for the KERNAL call "SETLFS"?
I get that putting 15 in the secondary address accesses the command mode, but why is it ALSO in the FA param? Doesn't the FA param reference a table of open files? They're the same file in examples 1 and 2... If you need a unique id for each concurrent action, wouldn't you just use the FA indexes in order?
Then in example 2 and 3, 5 is used as the SA for the first call... wait! Isn't 5 odd? Doesn't that mean a write operation? For that matter, how does the second OPEN (example 4) know about the 5? And why isn't it 2 like in the first example? or 4?
I feel like a priest is telling me how to invoke a magic ritual by chanting it's unknowable name. Obviously, that's not the actual case... computers are completely deterministic and will do exactly what you tell them to. I get that some of these magic numbers might mean something to some arcane interface you might see on the serial bus that C64 drives used to be connected to, but 99.9% of the time I would think the SDcard is what's being used.
I don't WANT to have PhD level knowledge of the C64's dos or it's kernal calls. I just want to know how the few calls I actually need to use work with the SDcard.
Sorry for the rant.
Re: Switching to R43 frustration
I'm trying to read up on it myself, and here's what I've got so far:
When you do OPEN 2,8,3,"FILENAME,S,W" the filename string is sent to address 3 (SA) of device 8 (FA), and the resulting "thing" that gets opened is bound to logical file #2 (LA).
When a disk drive specifically (including the SD card, which tries really hard to act like disk drives do) is device 8, it's the disk drive itself which defines addresses 0-14 to behave as slots you can open files into, on the drive side. The disk drive is also what's responsible for looking at the filename string you send it, and recognizing the ",S,W" at the end, and interpreting that as "we're specifically going to WRITE to this file, not read" instead of just four more characters in the filename itself.
BASIC is hardcoded to use 0 and 1 for LOAD and SAVE operations (respectively), definitely for LA but I'm also assuming SA too. There's no other constraints, and if you don't care about using the kernal's built-in loading and saving functions, you can probably just ignore those constraints entirely.
Again on disk drives (and SD card) specifically, address 15 acts as a command channel that governs the drive itself. Any command strings which operate on opened files will need to know what address (SA) the file was opened on, since remember, this is all on the drive side.
Note that on the strings in the examples, the first byte after the "P" is the same as the SA the file was opened into. That's how the command knows which file to operate on. This comes down to how the commands are formatted, you'd need to look this up in a manual for a 1541 or a 1571, but then it'll be the same for the SD card, unless the X16 documentation says something is unsupported.
It seems to be a common convention to just use the same value for LA and SA; it's not an actual requirement to do so. The reality is, instead of OPEN 15,8,15, you could do OPEN 2,8,15, and it'd still work fine (you're just binding it to logical file #2 instead of #15, but it's still the same command channel, which is SA 15).
When you do OPEN 2,8,3,"FILENAME,S,W" the filename string is sent to address 3 (SA) of device 8 (FA), and the resulting "thing" that gets opened is bound to logical file #2 (LA).
When a disk drive specifically (including the SD card, which tries really hard to act like disk drives do) is device 8, it's the disk drive itself which defines addresses 0-14 to behave as slots you can open files into, on the drive side. The disk drive is also what's responsible for looking at the filename string you send it, and recognizing the ",S,W" at the end, and interpreting that as "we're specifically going to WRITE to this file, not read" instead of just four more characters in the filename itself.
BASIC is hardcoded to use 0 and 1 for LOAD and SAVE operations (respectively), definitely for LA but I'm also assuming SA too. There's no other constraints, and if you don't care about using the kernal's built-in loading and saving functions, you can probably just ignore those constraints entirely.
Again on disk drives (and SD card) specifically, address 15 acts as a command channel that governs the drive itself. Any command strings which operate on opened files will need to know what address (SA) the file was opened on, since remember, this is all on the drive side.
Note that on the strings in the examples, the first byte after the "P" is the same as the SA the file was opened into. That's how the command knows which file to operate on. This comes down to how the commands are formatted, you'd need to look this up in a manual for a 1541 or a 1571, but then it'll be the same for the SD card, unless the X16 documentation says something is unsupported.
It seems to be a common convention to just use the same value for LA and SA; it's not an actual requirement to do so. The reality is, instead of OPEN 15,8,15, you could do OPEN 2,8,15, and it'd still work fine (you're just binding it to logical file #2 instead of #15, but it's still the same command channel, which is SA 15).
Last edited by DragWx on Mon Jul 17, 2023 2:22 am, edited 1 time in total.
Re: Switching to R43 frustration
OMG! I think I get it!
Ok, First, the 'Evensy oddsy" rule is bullshit, and just someone's convention for dealing with this. There are 16 SA channels, 0 to 14 are discretionary and you just need to match the assigned one with future commands on SA channel 15.
The FA channels are redundant as the SA channels cover the only ones you can practically use. (Supposedly, there are 30 or 32 FA channels.) That's just overkill. If you have more than a half dozen literal stream channels open at one time, you're already hosed! Scotty would already be yelling "The CPU can't take any more, captain!"
The OPEN command in BASIC also acts as a shell for at least the LISTEN KERNAL call, which sends a serial stream to the command channel (SA channel 15) With the first param being the DEVICE SA channel... which is the actual file descriptor that you would THINK the FA is. And I get why that is... FA is a GLOBAL descriptor while SA is the LOCAL descriptor for a device.
Realistically, it seems that the only time you actually need a unique SA within a device is if you're going to subsequently use the command channel to tell that device to position to a specific 32 bit address in the file. Otherwise, it's in sequential mode by default and your stream starts at position 0. To do that, you use LISTEN, then send 5 bytes with the SA first, then the 4 bytes of the 32 bit address in little endian order.
Ok, First, the 'Evensy oddsy" rule is bullshit, and just someone's convention for dealing with this. There are 16 SA channels, 0 to 14 are discretionary and you just need to match the assigned one with future commands on SA channel 15.
The FA channels are redundant as the SA channels cover the only ones you can practically use. (Supposedly, there are 30 or 32 FA channels.) That's just overkill. If you have more than a half dozen literal stream channels open at one time, you're already hosed! Scotty would already be yelling "The CPU can't take any more, captain!"
The OPEN command in BASIC also acts as a shell for at least the LISTEN KERNAL call, which sends a serial stream to the command channel (SA channel 15) With the first param being the DEVICE SA channel... which is the actual file descriptor that you would THINK the FA is. And I get why that is... FA is a GLOBAL descriptor while SA is the LOCAL descriptor for a device.
Realistically, it seems that the only time you actually need a unique SA within a device is if you're going to subsequently use the command channel to tell that device to position to a specific 32 bit address in the file. Otherwise, it's in sequential mode by default and your stream starts at position 0. To do that, you use LISTEN, then send 5 bytes with the SA first, then the 4 bytes of the 32 bit address in little endian order.