What is it?CBM-DOS is an operating system meant to run on computers equiped with an 8088 CPU or better.
BackgroundAt one time I was just curious how an operating system could be programmed and run. I started with using my own file system that was loosely based on the one used by various 6502 based Commodore drives like the 1541 and 8250. This and the goal to run it on my various Commodore PCs was the main reason to call it CBM-DOS. Just in case you don't know it, CBM stands for Commodore Business Machines.
After some time I decided that it could come in handy to have a FAT version as well. But I soon found out that it was quite some work to maintain two versions. The advantage: it learned me to keep the calls to the file system to a minimum to avoid extra work. But at a given moment I dropped the FAT version.
Then Michał Pleban managed to run MS-DOS 3.21 on a CBM 720 equiped with the so called Intel 8088 card. This card was developed by Commodore but never sold. There are not many cards around but because of the interest for it, I decided to create a new board with Eagle so one could produce real PCBs from it. Having such a card my self was a good reason to try to port CBM-DOS to the CBM 720/8088 combination as well.
Before even thinking about creating a new 8088 board, I had the idea about creating the PC-Box. For more info about the PC-Box, please visit this page. This idea for this piece of hardware was based on the SSE SoftBox: a small Z80 computer, no drives but equiped with an IEEE interface that enabled the Commodore CBM series to run CP/M 2.2 more or less. "More or less" because the CBM only acts as a terminal for the Softbox that does the actual computing.
The PC-Box can be as small as a PC board with just one LPT and COM port that, combined plus two ICs, can act as an IEEE interface. The board has to be told in one or another way how to act like a PC-Box and the idea is to use an external ROM. The advantage of an external ROM: it can be used on almost any PC board.
So my DOS should be able to run on:
- any IBM PC compatible ranging from 8088 and up.
- a CBM-II with an 8088 card.
- PC-Box: a stand alone PC with no video and keyboard and any CBM with an IEEE interface. The CBM will serve as terminal in the first place.
What to do about the differences?The CBM-II, PC and PC-Box are too different from each other to hope that I can run CBM-DOS out-of-the-box on all three systems. The main difference is how a PC and a CBM handle files: a PC has to do everything itself and a CBM just ask for a file and gets it from the drive. To be able to run MS-DOS on the 720/8088 combination a big part of the floppy disk is formatted as DOS and can not be used for the CBM. And that is something I dislike. IMHO CBM-DOS should access the drives in the same way as a CBM does. But how?
Displaying the directory will be one of the other differences. The original program handled all things it self: it loaded the various sectors, read and handled their contents and displayed the result. So should I write a DIR program for every system? And what about formatting a disk?
The idea is to use the same trick as used by CP/M and MS-DOS: one, and only one file handles all matters that concerns the differences in hardware like BIOS for CP/M and IO.SYS for MS-DOS. What ever system is mentioned above (or not mentioned yet) and is going to run CBM-DOS, this system dependent file is loaded in some way into memory and executed.
COMMON.PRGBy the time I figured out the above I already had a file named COMMON.PRG. This is a binary that contains a lot of useful routines that are not only used by the various system programs but also can be used by any programmer. Consider it as an equivalent of Windows' DLL, Linux's Shared Objects or MS-DOS' INT 21h. It is loaded at 0080:0000h and that is where the rest of every bit of other software think it will be. Its structure is simple: it starts with a jump table and after that table you will find the actual routines.
Why this file? Two of its subroutines are LookForFile and LoadFile. They make use of INT 13h and that makes them sector dependent. My first idea was to change INT 13h but I soon found out that INT 13h it self is already sector oriented and could not be used for loading files or subdirectories: that had to be done at an higher level. So I had to change COMMON.PRG at a higher level as well.
When taking LookForFile as example, this routine needs to check = read the directory. The program DIR needs to read the directory as well. So it is very logical to use a common routine for it. This means that in these two cases I have to adapt COMMON.PRG at only one place instead of two.
But what if the basic interrupts given by the BIOS have to be changed? In MS-DOS this is one of the main purposes of IO.SYS: alter an interrupt vector when needed. COMMON.PRG is started by the binary on the boot sector and the first thing it can do is changing interrupt vectors when needed.
General operationThe first and only file to be loaded and executed by the boot sector (PC), internal ROM (new 8088 card with 64 KB EPROM) or external ROM (PC-Box) is the file COMMON.PRG. The few things it does is:
- Setting various variables and pointers to some tables.
- Installing new or changed interrupts when needed.
- Loading Command, just loading, nor executing.
- Checking if Autostart exists and if so, run it using the program Bat. Bat on its turn starts Command.
- If Autostart does not exist, Common starts Command.
Command.prg can only be compared partly with MS-DOS' COMMAND.COM. Like COMMAND.COM it accepts commands from the command line but the main difference is how they are handled. COMMAND.COM has several internal commands like DIR, VER and TIME that IMHO could be handled like external commands. The advantage: a much smaller program than COMMAND.COM. The disadvantage: when using subdirectories, a PATH is a must then otherwise these now external programs can not be started.
The boot sectorA boot sector is only meant to be used by the PC. But then what about the CBM 720 and the PC-Box?
In case of the PC-Box the external ROM takes care of loading and executing COMMON.PRG. But before COMMON.PRG can be loaded at all, the CBM has to load and execute a program that turns it into a terminal for the PC-Box and signals this to the PC-Box. Only now the PC-Box can continue. Note: the PC-BOX could handle on its own but the CBM is fitted to operate in a multi-master surrounding and things could go wrong.
In case of the CBM 720 a program has to be loaded and executed that provides the routines to cooperate with the card and initializes the 8088 card. This is the trigger to loaded and execute COMMON.PRG.
The first function of the boot sector is to provide the BIOS with some data of the drive. This is necessary as the size of a hard or floppy disk can vary. The second function is to load the next program to be executed as the BIOS will load only one sector and that won't be enough to do what ever we want the computer to do. The boot sector is located at the very first sector of a drive.
First sector: * jmp Start 2 bytes * version identifier like "CBM-OS01" 8 bytes * Disk type 1 byte * CHS parameters - cylinders 2 bytes - heads 2 bytes - sectors 2 bytes * Number of BAM sectors 2 bytes * LBA pointer to the Boot program, all 0 when none 4 bytes * LBA start of the next partition, all 0 if none 4 bytes (1) * active partition, 0 if first one 1 byte (1) * Volume ID (time stamp) 4 bytes * disk label 13 bytes (1) not needed for a floppy
The DirectoryThe root directory starts at the second sector and is only one sector long. Except this particular sector, I've no plans of dedicating other sectors to directories or files. The reason for this is that in my experience any choice is always wrong: either too big or too small. If there is another sector needed for the directory then just allocate a free one and chain it to the last directory sector.
The structure of a directory sector should look like this:
* future use 32 bytes * 10 entries of 48 bytes each 480 bytes * + ---- * 512 bytesAn entry should look like this:
* file type 1 byte * name 26 bytes * always zero end 1 byte * future use 4 bytes * pointer to first sector, LBA 4 bytes * length of file 4 bytes * icon type 1 byte * date/timestamp, YYYYMMDDHHMISS 7 bytes + ---- 48 bytesFurther specs of the file typ:
HEX File type Directory shows --- --------- --------------- $00 Deleted DEL $x1 Text TXT $x2 Program PRG $x3 Binary BIN $x4 Batch file BAT $x5 Directory DIR $x6 MS-DOS COM file COM $x7 MS-DOS EXE file EXE $x8..xE = future use The four bits of the highest nibble are used as the 1541 uses them: value: 1 0 * bit 7: file is closed / still open * bit 6: file is locked / closed * bit 5: future use * bit 4: future use $3F = ignore file type during a search (only in program)Note: I'm not sure if I'm going to support COM and EXE files. But just in case...
In contrary to windows or Commodore, CBM-DOS won't allow spaces in the names. If they are used, the OS will replace them with an underscore. The reason: although Microsoft Windows allows it, in DOS mode various programs, commands and parameters encounter problems. I simply want to avoid these kind of problems.
The BAM tableThe first idea was to use an extended version of the link system as by various Commodore floppy drives: the first two bytes point to the next track/sector. In my case the first idea was to use four bytes to be able to handle Hard disk drives. The next step was not only using four bytes to point to the next sector but also four bytes to point to the previous one. Could come in handy in case of errors or looking for accidently deleted files.
When programming the boot sector I realized that this idea had one disadvantage: it would be very time consuming. I first had to load the sector in a reserved part of the memory so I could copy the last 504 real data bytes to their final destination. Whether it can be done with using DMA or not, the extra operation would cost valuable time. And the same for saving a file.
The data of a MS-DOS sector only holds data and therefore can be copied to its final destination in one go; no time consuming extra copy action needed anymore.
Realizing this I decided to combine the FAT and BAM format: the table reserves eight bytes for every sector: four for the next record, four for the previous one. An exception will be made for a floppy disk: only two bytes will be used for every pointer.
The BAM table itself starts at the third sector. As said above: for every sector four (floppy) or eight bytes (hard disk) have been reserved. Two/four bytes point to the next sector, the other two/four to the previous one. If a sector is free, all bytes are zero. The first two/four bytes of the last sector in the chain, are filled with $FF.
MS-DOS maintains a copy of the FAT table on every disk. The reason: if one table becomes corrupted, the other one can save the day. I decided to keep just one table. If times proofs that a copy is needed, I will add one.
To be continued.............
You can email me here.