Switching to R43 frustration
Re: Switching to R43 frustration
So, I'm back on the project I had to put on hold for being too unable to figure out the cult that is the file indexes.
The first FA used on a file needs to be unique in the range of 0 to 14. As a purist, I would never use 0. It's just wrong. Always burn the 0 entry. But that's just a personal peeve of mine, 0 should be reserved for "not connected / unused."
If the Command Channel is used for a subsequent command instruction for that channel, it also has to be unique. It makes SENSE to use 15 as it's guaranteed to only be needed for the one command function and it will be released. So you can basically reuse 15 at will for this purpose.
After that... I'm thinking you should never use LOAD or SAVE. Just OPEN the connection and use CHKIN or CHKOUT to decide at that point if it's reading or writing, do the reads or writes... then close the file.
I Think OPEN is supposed to set the carry flag on fail, but it doesn't. So if you're trying to read, what you do is set the A to $FF before you start reading and after you pull in the first 2 bytes (The location header, which you should use even if you're not using the LOAD command to do it automatically.) then you can test those bytes against $FF... they're either going to be the expected address, or $FFFF Not the address? Close the file and roll with whatever failure handling you want.
I don't think it matters if you have one leading / or two. Either condition means "From root." and the omission of it means "From the stored path." But here's the rub... YOU don't get direct access to the path. It seems to be private to the implementation and there's no interface except for changing the current path with the command channel using CD. When you do that, you can get the new path. But you gotta remember it in parallel to the system.
If I'm wrong on that, and there IS a direct KERNAL call for that, tell me!
I think I've found a "bug"? There is nothing stopping you from changing directory with the .. directory when you are already at the root. It won't be in the directory list, and the system will stop you from actually modifying the path, but I suspect the hostfs implementation lets that slide and breaks some kind of sync with the system. If I can find a better bug trail I'll post it.
The first FA used on a file needs to be unique in the range of 0 to 14. As a purist, I would never use 0. It's just wrong. Always burn the 0 entry. But that's just a personal peeve of mine, 0 should be reserved for "not connected / unused."
If the Command Channel is used for a subsequent command instruction for that channel, it also has to be unique. It makes SENSE to use 15 as it's guaranteed to only be needed for the one command function and it will be released. So you can basically reuse 15 at will for this purpose.
After that... I'm thinking you should never use LOAD or SAVE. Just OPEN the connection and use CHKIN or CHKOUT to decide at that point if it's reading or writing, do the reads or writes... then close the file.
I Think OPEN is supposed to set the carry flag on fail, but it doesn't. So if you're trying to read, what you do is set the A to $FF before you start reading and after you pull in the first 2 bytes (The location header, which you should use even if you're not using the LOAD command to do it automatically.) then you can test those bytes against $FF... they're either going to be the expected address, or $FFFF Not the address? Close the file and roll with whatever failure handling you want.
I don't think it matters if you have one leading / or two. Either condition means "From root." and the omission of it means "From the stored path." But here's the rub... YOU don't get direct access to the path. It seems to be private to the implementation and there's no interface except for changing the current path with the command channel using CD. When you do that, you can get the new path. But you gotta remember it in parallel to the system.
If I'm wrong on that, and there IS a direct KERNAL call for that, tell me!
I think I've found a "bug"? There is nothing stopping you from changing directory with the .. directory when you are already at the root. It won't be in the directory list, and the system will stop you from actually modifying the path, but I suspect the hostfs implementation lets that slide and breaks some kind of sync with the system. If I can find a better bug trail I'll post it.
Re: Switching to R43 frustration
I just did what is quickly becoming my favorite thing to do apparently, and checked the ROM to see what exactly it does.
OPEN sets carry and returns an error code:
- When trying to open to logical file #0 (huh? This is a surprise to me, but ok.) A=6
- When trying to open to a logical file # in use already, A=2
- When trying to open more than 10 files, A=1
- When trying to open device 1 (the Datassette), A=9
- When the device you're trying to open is not present (as in the physical device itself is not connected), A=5
After you OPEN a file, the next thing to do is to read the command channel on the disk drive to check if there were any errors relating to actually accessing the file from the disk. The 1571 manual does it like this:
Code: Select all
OPEN 15,8,15
INPUT#15,EN,EM$,ET,ES
CLOSE 15
Appendix B of the same manual outlines the various error codes, but the gist is, anytime EN >= 20, it's an error, and the thing you wanted to do didn't happen. This includes files not being found, running out of disk space, syntax errors with commands, and that thing when you try to overwrite a file that already exists but you didn't put the "@:" in the filename string.
I'm not 100% sure what you mean, but I can confirm in fat32.s that two leading slashes means "from root" and one leading slash means "from current directory", observing that "current directory" only changes when you specifically issue a command to change it, as far as I'm able to see (I can't check in the emulator right now).I don't think it matters if you have one leading / or two. Either condition means "From root." and the omission of it means "From the stored path."
What I mean by that is, if you loaded a program by specifying a path, it won't change the current directory to be that path, so any relative paths the program might try to access will be wrong in that situation; it's up to the user to correctly issue DOS commands to change to a program's directory, then load the program out of that directory for relative paths to be correct. (I don't know if anyone was getting tripped up by this, but it's important to point out anyway)
It looks like opening "$=C" and reading it is how you can get the current working directory, but it seems to be hardcoded to only work on channel 0 of the drive (SA=0).But here's the rub... YOU don't get direct access to the path. It seems to be private to the implementation and there's no interface except for changing the current path with the command channel using CD. When you do that, you can get the new path. But you gotta remember it in parallel to the system.
Also, while I was there, it looks like channel 0 on the drive (again, SA=0) is actually forced to always be read-mode when you open a file into it.
Re: Switching to R43 frustration
Yeah, OPEN makes sense being only able to issue errors about the openability of the file, the actual USE of the file hasn't even been determined yet, as that happens with either CHKIN (Read from a file) or CHKOUT (Write to a file.)
I think a lot of the confusion is BASIC just uses "OPEN" as the do all command that then segues into the other commands that actually do the lifting. And of course, all the documentation is BASIC centric, essentially hiding the idiosyncrasies of the actual command that actually does the thing in question.
/ or //? I've been trying it both ways, and it just doesn't matter. Likewise, putting a trailing slash does nothing either. Note, that the process I'm using to change the directory is:
Note: "jsr get_first_param" returns the index of the first parameter in the command line (After the command itself.) from the string XSH_CMD_LINE which is the full command line. That first parameter ends with the first space or the null terminator.
Instead of query for failure, I just immediately get the new path with $=C and print it on the screen as part of the prompt. It's certainly more than possible that other pathways that try to open a file with a path in it have other rules, and I've opened files with paths as well, and always with just a single slash for root, none for local. In fact, my current command shell project relies on this behavior because it has to start the command shell from the root directory with both the executable and the asset files it needs (sprites and tiles.) several directory hops away.
My process for opening files is to use CHKIN or CHKOUT (reading or writing) after calling SETLFS, SETNAM, and OPEN. After the reading or writing is done, CLOSE.
I wanna make a routine for that error check, though... knowing that much data about the failure would be useful.
I find that $=C doesn't care what SA you use, so long as it isn't 1 or 15! 1 is apparently hard coded for writing, 15 is hard coded for the Command channel. Everything else can be used for any read. I tried different SA values for $=C just to see if it had to be 0. It didn't care, just so it wasn't 1 or 15.
SA 0 being read only... I think it's actually 1 that is write only, and the only one that can BE write... all the rest except 15 can then, by the process of elimination, be considered "read only."
I think a lot of the confusion is BASIC just uses "OPEN" as the do all command that then segues into the other commands that actually do the lifting. And of course, all the documentation is BASIC centric, essentially hiding the idiosyncrasies of the actual command that actually does the thing in question.
/ or //? I've been trying it both ways, and it just doesn't matter. Likewise, putting a trailing slash does nothing either. Note, that the process I'm using to change the directory is:
Code: Select all
main_cd:
clc
lda #8
jsr LISTEN ; ($ffb1)
lda #15
jsr SECOND ; ($ff93)
lda #'C'
jsr CIOUT ; ($ffa8)
lda #'D'
jsr CIOUT ; ($ffa8)
lda #':'
jsr CIOUT ; ($ffa8)
jsr get_first_param
tax
@loop:
lda XSH_CMD_LINE,x
beq @end
cmp #$20
beq @end
jsr CIOUT
inx
bra @loop
@end:
jsr UNLSN ; ($ffae)
jsr get_path
; Copy the
rts
Instead of query for failure, I just immediately get the new path with $=C and print it on the screen as part of the prompt. It's certainly more than possible that other pathways that try to open a file with a path in it have other rules, and I've opened files with paths as well, and always with just a single slash for root, none for local. In fact, my current command shell project relies on this behavior because it has to start the command shell from the root directory with both the executable and the asset files it needs (sprites and tiles.) several directory hops away.
My process for opening files is to use CHKIN or CHKOUT (reading or writing) after calling SETLFS, SETNAM, and OPEN. After the reading or writing is done, CLOSE.
I wanna make a routine for that error check, though... knowing that much data about the failure would be useful.
I find that $=C doesn't care what SA you use, so long as it isn't 1 or 15! 1 is apparently hard coded for writing, 15 is hard coded for the Command channel. Everything else can be used for any read. I tried different SA values for $=C just to see if it had to be 0. It didn't care, just so it wasn't 1 or 15.
SA 0 being read only... I think it's actually 1 that is write only, and the only one that can BE write... all the rest except 15 can then, by the process of elimination, be considered "read only."
Re: Switching to R43 frustration
I'm back at my computer so I can actually test things now.
First of all, "{medium}{/path/}:{filename}{,options}" is the syntax for filenames, as far as I can tell.
{medium} defaults to 0 if omitted. {/path/} can be omitted, the current directory will be used to find the file. The ":" can be omitted if {medium} and {/path/} are both omitted.
After parsing, the ROM creates a PATH part and a FILENAME part. For "/GAME/DATA/:LEVEL1.DAT", PATH is "GAME/DATA/" and FILENAME is "LEVEL1.DAT". To actually locate this file in the SD card, this information gets converted to a FAT32 path by just gluing PATH and FILENAME together, so now you have "GAME/DATA/LEVEL1.DAT". (a relative path, by the way)
...the ROM makes no effort to check that the filename part is just a filename though, so you can also give this: "/GAME/:DATA/LEVEL1.DAT" (PATH is "GAME/" and FILENAME is "DATA/LEVEL1.DAT"), and this: "GAME/DATA/LEVEL1.DAT" (no PATH, but entire path is specified in FILENAME), and it all works the same. I don't think this is intentional though, because all documentation points to the user doing "/GAME/DATA/:LEVEL1.DAT", and the code in the ROM is set up to expect this too, and I think it's an unintentional side effect of how the current code works that the filename part can contain some path info.
Although, I have made the assumption that something was unintentional before and it turned out to be intentional all along, so I might be wrong here too. I didn't write the ROM code and I didn't write the emulator, so I'm at the mercy of what's implied in the documentation and in code comments and code architecture.
Anyway, the "CD" command is set up to expect the same syntax for paths too: "CD/GAME/DATA/:" ought to work how you think, and on actual hardware, I'll bet it does. However, in the emulator, the hostfs implementation expects you to always do "CD:GAME/DATA", and if the command starts as anything other than "CD:", it's interpreted as a "partition change" (which actually does nothing in the emulator).
So, this is something the devs will need to define and consolidate: Do we want to be able to put path information to the right of the ":"? Do we want the CD command to have a different syntax for specifying path (right of ":") or do we want to keep it consistent with OPEN (left of ":")?
So, this is kinda weird.
First of all, "{medium}{/path/}:{filename}{,options}" is the syntax for filenames, as far as I can tell.
{medium} defaults to 0 if omitted. {/path/} can be omitted, the current directory will be used to find the file. The ":" can be omitted if {medium} and {/path/} are both omitted.
After parsing, the ROM creates a PATH part and a FILENAME part. For "/GAME/DATA/:LEVEL1.DAT", PATH is "GAME/DATA/" and FILENAME is "LEVEL1.DAT". To actually locate this file in the SD card, this information gets converted to a FAT32 path by just gluing PATH and FILENAME together, so now you have "GAME/DATA/LEVEL1.DAT". (a relative path, by the way)
...the ROM makes no effort to check that the filename part is just a filename though, so you can also give this: "/GAME/:DATA/LEVEL1.DAT" (PATH is "GAME/" and FILENAME is "DATA/LEVEL1.DAT"), and this: "GAME/DATA/LEVEL1.DAT" (no PATH, but entire path is specified in FILENAME), and it all works the same. I don't think this is intentional though, because all documentation points to the user doing "/GAME/DATA/:LEVEL1.DAT", and the code in the ROM is set up to expect this too, and I think it's an unintentional side effect of how the current code works that the filename part can contain some path info.
Although, I have made the assumption that something was unintentional before and it turned out to be intentional all along, so I might be wrong here too. I didn't write the ROM code and I didn't write the emulator, so I'm at the mercy of what's implied in the documentation and in code comments and code architecture.
Anyway, the "CD" command is set up to expect the same syntax for paths too: "CD/GAME/DATA/:" ought to work how you think, and on actual hardware, I'll bet it does. However, in the emulator, the hostfs implementation expects you to always do "CD:GAME/DATA", and if the command starts as anything other than "CD:", it's interpreted as a "partition change" (which actually does nothing in the emulator).
So, this is something the devs will need to define and consolidate: Do we want to be able to put path information to the right of the ":"? Do we want the CD command to have a different syntax for specifying path (right of ":") or do we want to keep it consistent with OPEN (left of ":")?
This seems to be another discontinuity between the ROM and the hostfs implementation in the emulator. The ROM definitely checks for SA=0 when the filename is "$", and on all other SA values, it forces this to be interpreted as a literal file called "$" and not the command for "give me a directory listing".I find that $=C doesn't care what SA you use, so long as it isn't 1 or 15! 1 is apparently hard coded for writing, 15 is hard coded for the Command channel. Everything else can be used for any read. I tried different SA values for $=C just to see if it had to be 0. It didn't care, just so it wasn't 1 or 15.
At least according to the rom, SA=0 is always a read-only channel. SA=1 is always a write-only channel (I misread this before, otherwise I would've mentioned it in my previous post). SA=2..14 can be either/or, and depends on what the options following the filename are: "MYDATA.DAT,S,R" (or just "MYDATA.DAT") for reading, "MYDATA.DAT,S,W" for writing, and "@:MYDATA.DAT,S,W" for writing with overwriting being ok.SA 0 being read only... I think it's actually 1 that is write only, and the only one that can BE write... all the rest except 15 can then, by the process of elimination, be considered "read only."
Re: Switching to R43 frustration
More wackiness that goes on:
I noticed that the "$" file that serves as the directory listing is opened exactly as if it was literally a file named "$", but it isn't. I saved out a file with the name "$" and it appears as an actual file, with whatever I wrote into it still there. But of course, opening it and reading the contents doesn't get the actual directory. You have to delete it, then the "phantom $ file" is back and you can read the directory.
Where is the actual parsing taking place? I haven't been bothering with a ":" except in the case where I need to add the "@" for overwrite, and then I've not tried to do a "compound" filename. So if I'm trying to write that "$" file, it's just "@:$" and the file goes into the current directory. In the shell tool I'm writing, using "cd /bin/xsh" will take you directly to /bin/xsh from anywhere, but "cd bin/xsh" must be executed from root. I suppose I could try "cd /:bin/xsh" but that just seems arcane and overly semantic. When it starts up, it loads (For example.) the mouse sprites with the text literal "mouse_sprites: .byte "/bin/xsh/mouse.spr" and that goes right into SETNAM. (Note, I have ca65's petscii translation turned off, so the lower case filename is lower case ascii... Like it freakin' should be.)
I think I'm going to wait until I have actual hardware before really doing a deeper dive into this... I'm happy with the way it currently seems to work and I can continue to develop my project. It's pretty sweet! Today I ran a program from the shell by typing it's name to execute it and it ran, replacing the shell entirely, then upon exiting THAT program through rts, the shell was restarted from the launch stub that was still resident in banked RAM. That loop just continues for as many time you want to launch a compatible program. (It has to turn off it's int handler, set the RAM bank back to 0, then execute the rts instruction.) I could have entire suite of related programs this way. Edit a file with the editor, close that then run the compiler, etc. Just like in a real computer. Heh.
I noticed that the "$" file that serves as the directory listing is opened exactly as if it was literally a file named "$", but it isn't. I saved out a file with the name "$" and it appears as an actual file, with whatever I wrote into it still there. But of course, opening it and reading the contents doesn't get the actual directory. You have to delete it, then the "phantom $ file" is back and you can read the directory.
Where is the actual parsing taking place? I haven't been bothering with a ":" except in the case where I need to add the "@" for overwrite, and then I've not tried to do a "compound" filename. So if I'm trying to write that "$" file, it's just "@:$" and the file goes into the current directory. In the shell tool I'm writing, using "cd /bin/xsh" will take you directly to /bin/xsh from anywhere, but "cd bin/xsh" must be executed from root. I suppose I could try "cd /:bin/xsh" but that just seems arcane and overly semantic. When it starts up, it loads (For example.) the mouse sprites with the text literal "mouse_sprites: .byte "/bin/xsh/mouse.spr" and that goes right into SETNAM. (Note, I have ca65's petscii translation turned off, so the lower case filename is lower case ascii... Like it freakin' should be.)
I think I'm going to wait until I have actual hardware before really doing a deeper dive into this... I'm happy with the way it currently seems to work and I can continue to develop my project. It's pretty sweet! Today I ran a program from the shell by typing it's name to execute it and it ran, replacing the shell entirely, then upon exiting THAT program through rts, the shell was restarted from the launch stub that was still resident in banked RAM. That loop just continues for as many time you want to launch a compatible program. (It has to turn off it's int handler, set the RAM bank back to 0, then execute the rts instruction.) I could have entire suite of related programs this way. Edit a file with the editor, close that then run the compiler, etc. Just like in a real computer. Heh.
- ahenry3068
- Posts: 1136
- Joined: Tue Apr 04, 2023 9:57 pm
Re: Switching to R43 frustration
This is very useful info. I wish the file I/O was better documented at a contemporary
level..... But the Commodore 64 docs are interesting
level..... But the Commodore 64 docs are interesting
Re: Switching to R43 frustration
Every system that's tried to integrate modern FAT32 with CBM's drives' DOS conventions has done so slllllightly differently, and the X16's CMDR-DOS is no exception to that rule. And even the 1581 had to figure out a way to integrate the need for organization of larger storage devices into the conventions of the 1571 and 1541... which in turn inherited their behavior from IEEE-488-based drives like the 4040 and 8050.
Here's a fun article from Greg Naçu about trying to write code to handle the issue with his C64OS file handling systems. https://c64os.com/post/softwareiecgap
Here's a fun article from Greg Naçu about trying to write code to handle the issue with his C64OS file handling systems. https://c64os.com/post/softwareiecgap
Re: Switching to R43 frustration
It's in dos/parser.s. This is both where command parsing and path/filename parsing/splitting/mixing/salad is happening.
It helps to imagine the built-in SD card drive as though it were just an external device you plugged into the disk drive port, with its own firmware and everything. It's neither the Kernal nor BASIC, but the drive itself that parses the paths and such, from the strings you send it.
Re: Switching to R43 frustration
Oh, yeah, I should have know the parser was in the parser module. In hindsight... yeah.
Anyway, I was wondering what would happen when I got a path that was longish. I noted that in BASIC, the DOS calls just shortened the path to 16 characters. Well, that happens here, too. As you can see in this screenshot, the "full path" is still stored, and you need the full path if you're going to type it in in one go, but you can always do it incrementally as well.
I think a lot of "shell development" is going to be dodging around the limits of the fat32 implementation in CBM DOS.
Another detail that you can't see here is that there are only 2 "file types" reported, DIR and PRG. as such, I can't tell the executable files from the "regular" files without opening them and looking for the header bytes. But I can detect DIR entries with precision, so the next step is to color code those blue so the user knows they're directories.
Anyway, I was wondering what would happen when I got a path that was longish. I noted that in BASIC, the DOS calls just shortened the path to 16 characters. Well, that happens here, too. As you can see in this screenshot, the "full path" is still stored, and you need the full path if you're going to type it in in one go, but you can always do it incrementally as well.
I think a lot of "shell development" is going to be dodging around the limits of the fat32 implementation in CBM DOS.
Another detail that you can't see here is that there are only 2 "file types" reported, DIR and PRG. as such, I can't tell the executable files from the "regular" files without opening them and looking for the header bytes. But I can detect DIR entries with precision, so the next step is to color code those blue so the user knows they're directories.
- Attachments
-
- xsh_dir_length.png (45.33 KiB) Viewed 18198 times
Re: Switching to R43 frustration
One of my goals here is to create an environment that makes it easier to edit the plethora of file assets needed to create a game on the X16. For that you need a shell that lets you navigate the file system, then a way to run the tools that edit the files that define game.
This first shot is the user about to start editing a part of the game world for "rampart pass" (A game I'm working on.) then the editor itself, then when the user is done, closing the editor with the "X" in the upper right drops them right back to the shell.
This first shot is the user about to start editing a part of the game world for "rampart pass" (A game I'm working on.) then the editor itself, then when the user is done, closing the editor with the "X" in the upper right drops them right back to the shell.