Jump to content
IGNORED

Atari DOS 1 Source Listing?


Recommended Posts

1 hour ago, pcrow said:

And I've found and fixed the DOS 1 bug that annoyed me in the first place and inspired this project:  If you create a file with 256 or more sectors, the directory listing only shows the low-byte of the sector count.  It took a while to find because I was looking in the wrong place.  All the code that manages the file sector counts was right (except for an initialization bug that I also fixed, but appeared to be harmless).  I finally looked at the directory sector in a debugger and saw that the count was right there, too.  The bug was in reading the directory.  They left off a ",X" on the instruction to read the high byte of the sector count, which seems to have caused it to always get a zero (fortunately).  That's fixed, and now directory listings are correct.

 

Of course, the DOS 2 listings have these bugs fixed, but now DOS 1 has it, too.

I love the work you are doing and that you have taken up this project.  It's great to have valid sources for the binaries.

 

In addition to the fixed version, have you kept a source code release that results in a binary perfect file with bugs and all?

 

Best Regards,

 

Brian

 

Link to comment
Share on other sites

8 hours ago, reifsnyderb said:

In addition to the fixed version, have you kept a source code release that results in a binary perfect file with bugs and all?

Absolutely!

 

The GitHub repository has three versions: The original as close to what I think they were (character perfect apart from a few added comments), cleaned up (easier to assemble), and modified.

  • Thanks 1
Link to comment
Share on other sites

Interesting assembly tidbit:

 

I see a bunch of places in the DUP code where one subroutine ends with calling another subroutine and then immediately returning.  So it's a JSR followed by an RTS.  It occurred to me that it should be exactly the same to just change the JSR to a JMP and remove the RTS.  Normally that would work fine, but there are functions that in their error handling pops off the return address and jumps to the menu, which behaves differently if the stack has one fewer return addresses on it than expected.

 

I expect I can convert some of them, but even things that look like a brain-dead optimization may not work as expected.

 

I also thought I could save some bytes by using tabs instead of spaces between the columns of the menu, but it doesn't reset the left margin, so spaces are needed to avoid a potential behavior change.

Link to comment
Share on other sites

The current version reports 28934 bytes free in BASIC, as opposed to 28814 bytes free with stock DOS 1, a savings of 120 bytes.  The bigger savings is the 9 sectors saved in DOS.SYS, which will surely save us tons of money in buying 90K floppy disks unless something has changed since 1979.  :)

 

Are there any other known bugs in DOS 1 that should be fixed?  Should burst I/O be backported from DOS 2?

 

Did you know that binary load files in DOS 1 start with 84 09 (or $0984 as a word)?  I've seen that documented before, but never heard why those numbers were selected.  I could make it also accept $FFFF, but I'm trying to make it smaller, not bigger.

  • Like 2
Link to comment
Share on other sites

4 hours ago, pcrow said:

I see a bunch of places in the DUP code where one subroutine ends with calling another subroutine and then immediately returning.  So it's a JSR followed by an RTS.  It occurred to me that it should be exactly the same to just change the JSR to a JMP and remove the RTS.  Normally that would work fine, but there are functions that in their error handling pops off the return address and jumps to the menu, which behaves differently if the stack has one fewer return addresses on it than expected.

OK, I was wrong there.  Looking further, the code that pops off the return address before aborting is pointless, as it jumps to the menu display code that starts by resetting the stack pointer.  The reason my code didn't work is that I killed an RTS after a JMP where it didn't have a label, but there was a BRA *+5 before the JMP that skipped over it, so I shouldn't have removed the RTS.  Though I was able to refactor things to reverse the logic of the branch to go to an identical JMP elsewhere and eliminate the duplicate JMP instruction.

 

I could go further in optimizations, but I think this is a good stopping point.  There are several subroutines that are always followed by a jump to the menu, so the jump could instead go in the subroutine once.  There are some subroutines that are only used once that could be inlined if that doesn't push branch targets out of range.

 

As it is, there's an additional 154 free bytes, it's 9 sectors shorter, and at least one bug is fixed.  So unless someone asks for more, I think this is it for now.

Link to comment
Share on other sites

8 hours ago, reifsnyderb said:

I made an assumption that @pcrow was talking about optimizing DOS 2.  Then, @kheller2 mentioned a DOS 2.5D.  So, my post was a suggestion to use 2.6f or 2.8f as a starting point.

None of those can do ED or DD.    2.0D was always interesting to me, especially finding a 815 master image.  D always seemed to be just a hacked/patched version of S to support 256 byte sectors.  I even think there were a few public patches to convert S to D.  And for some reason I think S DUP has no problems with reading D DD images using D dos.sys. IE not much is different in the DUP, it’s the DOS that had the mods.  But it’s been a while since I played with them and could be wrong. I thought it was odd Atari would release a D version that could only ever do DD and not support S/D. But then again the 815 disks were incompatible with anything else so why bother with a S mode. 

Link to comment
Share on other sites

In theory if DUP used high level interface, ie CIO and not direct calls or r/w operations on the disk then it could be D/S agnostic.

Been a long time since I've browsed any source - I guess that all the burst mode stuff is in DOS.

Binary load I suppose should just be simple file operations.

Directory - we can do that stuff from simple Basic operations to the D device only so DUP should be much the same.

Link to comment
Share on other sites

DOS 2.5 was an update from Atari to support Enhanced Density on the 1050 after DOS 3 was rejected by pretty much everyone.  I haven't looked, but I assume it has the same double-density support that DOS 2.0s has, though I don't know how useful it is, as I've never looked at the differences between 2.0s and 2.0d.

 

DOS 2.6f and several other versions that look similar are simply third-party hacks to add new features to DUP.SYS on top of DOS 2.0s.  These were not released by Atari.  There's also a DUP.SYS that says "David Young modified" that has "SUPERDUP" for duplicate disk that copies everything without looking at the bits in sector 360, so it works for copying non-DOS disks that aren't otherwise copy protected.

 

MyDOS is mostly compatible with DOS 2, but was written by another company, adding support for large disks and subdirectories, as well as double density.  It is not compatible with DOS 2.5 for enhanced density disks.

 

DOS 1 sector chains put a file sequence number in the last byte of the sector instead of the number of bytes used, so only the last sector could be less than full.  (I believe on the last sector, the high bit of that byte was set and the rest indicated how much was used or free.)  That's why DOS 2 sets an additional flag bit on files in the directory to say that they're DOS 2 files.  DOS 2.0s and even DOS 2.5 have read compatibility for DOS 1 files.  MyDOS does not have compatibility with DOS 1 files, despite otherwise appearing to be equivalent to DOS 2 for most purposes.

Link to comment
Share on other sites

DUP.SYS is almost entirely independent of DOS.SYS.  There are a few points where that's not true.  Duplicate disk reads sector 360 to see which sectors are allocated.  And, of course, it's designed to load immediately above DOS.  That's about it for DOS 1.  For DOS 2, option H to write DOS files probably has to save DUP.SYS.  In DOS 1, it just opens DOS.SYS for write and closes it, and the DOS level watches for that and writes DOS.SYS for you when it's opened.  Try this and get some really weird results:

  • Boot into BASIC with DOS 1 (also verified in DOS 2.0s)
  • Enter DOS
  • Format a blank disk in drive 2
  • Enter BASIC
  • Write a one-line program, such as: 10 ? "OK"
  • SAVE "D2:DOS.SYS"
  • Enter DOS
  • Do a directory listing on D2:
  • Note that DOS.SYS is the regular length of DOS.SYS plus the length of your BASIC program

I believe this was done to avoid DUP needing to see what sector DOS.SYS starts on and needing to know the end address for DOS.SYS.  Shifting this from DOS to DUP would complicate things but slightly reduce the memory footprint of DOS, which would be a good thing.

 

So, yeah, apart from duplicate disk, DUP does not do any raw sector I/O (verified in DOS 1 assembly since I have that up)
 

Link to comment
Share on other sites

I think if I am to start playing with a different version of DOS, it might make the most sense to do MyDOS, as that's still widely used today.

 

Maybe I should port the DOS 1 "DEFINE DEVICE" option over.  :)  That was actually a cool feature of DOS 1 that was almost never used and dropped in DOS 2.  I suspect they had to drop it because it was fundamentally part of DUP.SYS, not DOS.SYS, and it wouldn't work if DUP.SYS wasn't kept loaded.  The answer might be to make DUP.SYS and DOS.SYS more tightly coupled, or to go further and make an XIO call for define device, which could make it more useful, as programs would be able to define devices with it.

 

Actually, extracting the define device feature so that it can run entirely separately, and include defininging devices in terms of things other than DOS files could be useful.  For example, in emulation, you might want to define a device as a file on H: instead of D:.  Or perhaps pointing to N: on a FujiNet.  But I'm still not clear on when it would really be useful.

Link to comment
Share on other sites

4 hours ago, pcrow said:

it just opens DOS.SYS for write and closes it, and the DOS level watches for that and writes DOS.SYS for you when it's opened

I just tested, and MyDOS does this, too.

DOS XE does not do this (there the file name is DOSXE.SYS, but if you create one outside of the DOS menus, it's just a file).

Atari DOS 3 and Atari DOS 4 do not do this, either (DOS 4 was the leaked DOS written for the 1450XLD)

 

But in general, there's no reason you can't repackage DUP into an XEX file relocated to a higher address, and it should work for most functions with any DOS.  I suppose a crazy idea would be to take DOS 1 DUP, remove duplicate disk, define device, and write DOS files, and make it work under SpartaDOS.

Link to comment
Share on other sites

8 hours ago, kheller2 said:

2.0D was always interesting to me, especially finding a 815 master image.  D always seemed to be just a hacked/patched version of S to support 256 byte sectors.  I even think there were a few public patches to convert S to D.

@bob1200xl once posted a dump of an 815 master disk with the clarification "DOS4815 is the 815 Master Diskette" a few posts down in that thread because the linked post contains two ATRs. 

  • Like 1
Link to comment
Share on other sites

Back to DOS 1, I had made a note to test out AUTO.SYS, as I've heard it said that DOS 1 doesn't support AUTORUN.SYS, but it does support AUTO.SYS.  Well, not really, it turns out.  There are some issues.

 

To start, binary load files in DOS 1 start with 84 09 instead of FF FF.  I would love to know why that was picked.  It's not hard to modify files to switch the header to the DOS 1 version.

 

Next, the code in DOS 1 will execute a run address at 02E0, but it has nothing to execute init at address 02E2.

 

And finally, it does not execute the run address on AUTO.SYS.  This is an outright bug, as it obviously should.  It loads the file into memory, but bypasses the code that handles the run address.

 

As a test, I used Alien Ambush, which loads at $3000-$3ffb and then executes at $3000.  Loading it from the menu option works and starts the game.  Renaming it to AUTO.SYS loads it into memory, and then using the "run at address" menu option to jump to 3000 starts the game.  But in general AUTO.SYS is broken.

 

I've fixed the run address bug on AUTO.SYS in my dos1modified.asm and pushed that to the repository.  So now we finally have working AUTO.SYS for DOS 1 as intended.  I'm not putting the init address support in, as that's more a missing feature than a bug.

 

So another 45-year-old bug fixed!

  • Like 4
Link to comment
Share on other sites

84 09 = DH (Dos Header) - if we assume letters of the alphabet being represented.  Maybe.

 

At the time, there would have been few established standard Atari headers.  Basic has 00 00, so maybe high bit set on first byte flags a machine code file.

Link to comment
Share on other sites

2 hours ago, Rybags said:

84 09 = DH (Dos Header) - if we assume letters of the alphabet being represented.  Maybe.

 

At the time, there would have been few established standard Atari headers.  Basic has 00 00, so maybe high bit set on first byte flags a machine code file.

If it's high-bit set and letters of the alphabet, then it's DI, not DH, for the 4th and 9th letters.  If it's an address, $0984 isn't even a label in the code, though it could have been when the number was picked, and the code shifted in development.  I would guess it was arbitrary, and the developer picked it because it meant something to him.  I know that's true for some magic numbers in code I wrote.  I would think September of 1984, but this was released in 1979.

 

The change to $FFFF means it can be tested in fewer bytes of code.  For example:

  INC DBUF
  BNE NOTBIN
  INC DBUF+1
  BNE NOTBIN

 

Link to comment
Share on other sites

9 hours ago, pcrow said:

And finally, it does not execute the run address on AUTO.SYS.  This is an outright bug, as it obviously should.  It loads the file into memory, but bypasses the code that handles the run address.

Technically it is possible to get a working AUTO.SYS with stock DOS 1.  You have to have the code load a patch on top of DOS to intercept the code and have it run the program.  Then if you want DOS to still work, the program would have to restore whatever you clobbered.  Quite a hack, and pointless once DOS 2 was released.

Link to comment
Share on other sites

FF FF makes more sense IMO in that you won't run into the situation where a load segment causes an error.

$0984 is a perfectly valid start address though you'd be needing a boot menu loader so you're not corrupting the DOS.

 

  • Like 1
Link to comment
Share on other sites

I did a bit more testing.

 

I had some weird problems that turned out to be a bug in atrfs with creating one-sector DOS 1 files, which I've fixed.  (Atrfs if my program that lets you mount Atari images as native file systems under Linux or MacOS using FUSE for user-space file systems.  There's another long thread on it.)

 

With my fix, DOS 1 does AUTO.SYS just fine with the caveat that DOS 1 does not support init addresses in binary load files, only run addresses.  The way I implemented the fix, a return at the end of the loaded code is just fine.

 

For DOS 2, AUTORUN.SYS handles INIT and RUN addresses correctly.  I thought I saw somewhere that only INIT was supported, but experimentation shows that's not true.

 

As mentioned previously, DOS 2 and DOS 2.5 have support for reading DOS 1 files.  DOS 1 does the sector chaining slightly differently, which has the advantage of not wasting a sector if the last sector contains 125 data bytes.  I wish they hadn't changed that, but I think they decided it made append easier to implement.  However, DOS 2 does not have any support for DOS 1 binary load files, so if you have any, you have to manually convert the first to bytes to FFFF if you want to use DOS 2.

 

Perhaps it was intentional for DOS 1 to not run AUTO.SYS, and only load it, but that seems rather dumb.  Though it would explain why "RUN" was added to the name in DOS 2.  Either way, I'm leaving my change in the dos1modified.asm and dos1mod.atr files in the repository.

  • Like 1
Link to comment
Share on other sites

Looking at the one unique feature of DOS 1: "N. DEFINE DEVICE"

 

This is a pretty cool feature.  You can set up a device handler and redirect to a file or other device.

 

An obvious use would be: P:,D:PRINT.LOG

 

Some quick testing with setting that shows that using the LPRINT command in BASIC adds text lines to D:PRINT.LOG.

 

Perhaps a more curious example would be: C:,D:CSAV.BAS

 

Then write a quick BASIC program and save it with CSAVE.  This is the exact same as using SAVE "D:CSAV.BAS" except that the file is, I think, 11 bytes shorter.  That's because the SAVE command (and CSAVE) includes the command used to save the program at the end of the file.  You can, of course, also use CLOAD with that redirection to read the file.  I once had a game that would only save to cassette, and I didn't have a cassette drive.  I think this would have solved the problem.

 

But it doesn't end there.  Running in the atari800 emulator, I set up the H: device to be my current directory and made it writable.  Then I used define device with C:,H:CSAV.BAS.  I could then use CSAVE and CLOAD, and it went to the file on my local file system.

 

That points out a key detail here: The define device option really has nothing to do with DOS at all, though it was probably rare to ever use it other than redirecting P: to a file or possibly C:.  So why was it dropped in DOS 2?  The obvious answer is that it wasn't popular, but I don't think that's the real answer.  I think the real answer is that it was part of DUP, and it needed to stay resident in memory to be useful, so with DOS 2 loading DUP.SYS separately, it didn't make sense anymore.

 

This suggests another project: Extract the define device feature from DOS 1 to be a standalone program that can work with any DOS.  It shouldn't be too difficult.  The only question is where to put it.  Probably the best answer is to make it relocatable and bump up MEMLO, though that would mean loading DUP would kill it.  I guess in part it depends on how large it turns out to be.

  • Like 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...