PDA

View Full Version : Under the hood of CP/M 2.2 - Disk Types for JAIR 8080



Josh Bensadon
October 16th, 2016, 12:00 PM
I'm having trouble finding documentation on the Drive Parameters Block.

I am looking for more information to explain the use of the Extent Mask (EXM) and the Check Area Size (CKS).
Also looking for confirmation on how CP/M decides on when to use 16 bits or 8 bits to allocate the clusters.
I believe it just looks at the Total Storage Capacity (DSM) and if this number is greater than 255, it uses 16 bits in the directory extents.

I'm having trouble with CP/M 2.2, in how it accesses large disks. It seems like small files are correctly being copied to the virtual disk, but large files are not.
I'm seeing a limit of 32K, which I'm going to check shortly, but I believe it is when a 2nd directory extent is being used. I am then seeing CP/M trying to write to track 240ish or track 160ish... clearly tracks that are way beyond the size of the disk.

There is another question... in the BIOS, I've only seen examples of where an 8 bit sector is passed to the BIOS in register C. But the DPB allows for 16 bits in counting the numbers of Sectors per Track. Does this mean I should be using register pair BC? I have not come across any disk types with more than 256 sectors per track, but I guess it could happen?

The above questions are related to my S-100 board JAIR 8080 that is a single board computer / cpu board replacement for the ALTAIR & IMSAI systems. It uses an SD card to simulate drives. Works flawlessly with the SSSD disk type, but the bigger disks are still a little mysterious to me.

Thank you for any help or suggestions.

Cheers,
Josh Bensadon

Chuck(G)
October 16th, 2016, 12:55 PM
EXM is tied into the block size (as dictated by BSH and BLM) as well as the number of blocks on the drive (DRM).

Observe that in a directory entry (not to be confused with an FCB, despite the similarity), one has 16 bytes in which to enumerate the blocks belonging to a file. Now, if you're working with the default CP/M distribution disk, a block is 1024 bytes (BSH 3, BLM 7) and there are 242 blocks on a disk ("A1" format), so a directory entry can describe 16KB or 128 128-byte records. (CP/M always uses a fixed logical sector size of 128 bytes). This is an "extent". If the file is longer than 16K, a new directory entry is created and subsequent block numbers are entered there, up to a maximum of 16K and so on. Each new directory entry has its "extent" field incremented to show what part of the file it maps. The first extent is 0, the second is 1 and so on. (You can see the extent number in the directory entry in the byte immediately following the file name).

Now, suppose that we have a larger diisk to describe; say one that is twice as large as the (250K) default. We can change the block size to 2048 by setting BSH 4, BLM 15 (the two are related--BLM is simply a mask that represents the value (2**BSH)-1. The number of blocks on the drive doesn't change; it's still 242, but each block is twice as large. So, 16 blocks now describe 32KB and the directory entry has to reflect that. The method is to set the extent number =1 to the first full directory extent, and 3 for the second, and so forth. To indicate this, we set EXM to 1 in the DPB, which is essentially mask of bits to ignore when searching for directory entries.

Let's double the size of the disk again, but keep the block size at 2048. We now have 484 (DSM) total blocks on our disk. But we have a problem--to represent this number requires two bytes in the directory block list. So we can hold only 8 block addresses and our directory extent still describes 32KB and EXM remains at 1. And so forth.

There is one notable exception to this--where we have fewer than 256 blocks on a disk and the block size is 2048 or greater. We can set EXM = 0 in the DPB and so each directory extent still describes 128KB, with the second 8 bytes of the block list left unused. This isn't frequently done, but it does exist in practice.

As far as mapping larger drives (recall that CP/M originated as a floppy disk system), you have only BIOS two routines to set the disk address; SETSEC (Set sector) and SETTRK (Set track). Although, there has been discussion in the past if the value of the sector number is a word or a byte, the safe thing to do is to assume that it's a byte. Track number is a word. That gives you 2**24 128-byte sectors maximum to play with. You can use these two values to compute a physical sector address (and offset if your physical sector is larger than 128 bytes) any way you desire. If you're using a physical sector larger than 128 bytes, you'll have to perform your own blocking and deblocking of 128-byte "logical" CP/M sectors (Note the value in the C register on the BIOS write call is designed to help you speed things up a bit).

And boy, are there some bizarre sector address calculation routines out there. I should know.

Josh Bensadon
October 16th, 2016, 07:36 PM
>EXM is tied into the block size (as dictated by BSH and BLM) as well as the number of blocks on the drive (DRM).

Right, I see that on page 34 of The Programmer's CP/M Handbook. I didn't understand it, but from your post, I think I'm begining to.

So, extents are numbered 0, 1, 2, 3... for each 16K (that's 16 x 1K block) for the "A1" format. That makes perfect sense.

But when we double the size of the disk by doubling the size of each block (ie 2K blocks), why are we counting the extents 1, 3, 5, 7....?
The sequence of directory entries could have been followed with a simple counting of 0, 1, 2, 3...
I suppose the answer is deep inside CP/M and I don't need to know why so long as I understand the system.

So, if we keep doubling the block size, will the extent counting look like this....
4K (EXM=3) 3, 7, 0xB, 0xF...
8K (EXM=7) 7, 0xF, 0x17, 0x1F...
16K (EXM=0xF) 0xF, 0x1F, 0x2F, 0x3F...

I can see how the extent does make sense. When the extent of 1 is reached, it indicates we can have up to 32K regardless if we are using 1K blocks and taking two directory entries, each with 16K, or using 2K blocks and one directory entry. But now I'm just guessing at what's happening under the hood.


>The method is to set the extent number =1 to the first full directory extent, and 3 for the second, and so forth.

When you say full directory extent, do you mean a full directory block list? If so, then what is the extent set to when the block list isn't full?


>Let's double the size of the disk again, but keep the block size at 2048. We now have 484 (DSM) total blocks on our disk. But we have a problem--to represent this number requires two bytes in the directory block list. So we can hold only 8 block addresses and our directory extent still describes 32KB and EXM remains at 1. And so forth.

I understand the part about doubling up the bytes to make words. So from 16 bytes, we now have just 8 words (little endian).
But if we can only describe 8 blocks of 2K, that's 16K. I'm confused why you would say 32K?



>There is one notable exception to this--where we have fewer than 256 blocks on a disk and the block size is 2048 or greater. We can set EXM = 0 in the DPB and so each directory extent still describes 128KB, with the second 8 bytes of the block list left unused. This isn't frequently done, but it does exist in practice.

I'm not sure I follow this. For a directory extent to describe 128KB using 16 blocks in the list, that's 128/16 = 8K blocks. I mean to say, when you talk about the directory extent describing 128K, then I must assume you're only talking about 8K block size, but your sentence includes 2K, 4K, 8K and 16K block sizes (when you described it as "2048 or greater"). Sorry if I'm taking things literally, I'm a programmer, so I'm sure you'll understand.

>SETSEC (Set sector) and SETTRK (Set track)

Right, I understand from the eyes of CP/M the world is made up of X number of sectors (always 128 bytes large) and Y number of tracks.
Where X starts at 0 and does not go higher than 1 less the value of the SPT (Sectors Per Track).
And Y starts at 0 and increments indefinitely (after all sectors on that track are read) until the largest number of blocks is reached (skipping over the reserved tracks of course).

>Although, there has been discussion in the past if the value of the sector number is a word or a byte, the safe thing to do is to assume that it's a byte.

Given that I have not yet seen a DPB with an SPT of more than 256, I can live with this assumption.

>Track number is a word. That gives you 2**24 128-byte sectors maximum to play with. You can use these two values to compute a physical sector address (and offset if your physical sector is larger than 128 bytes) any way you desire. If you're using a physical sector larger than 128 bytes, you'll have to perform your own blocking and deblocking of 128-byte "logical" CP/M sectors (Note the value in the C register on the BIOS write call is designed to help you speed things up a bit).

Interesting, I have not heard of the C register before. Looking at page 275 of the aforementioned book, I see how they use C to indicate Directory writes. But I don't need to worry about this, all my writes are cached in 512 byte sized SD Sectors and they apply to the SD card when ever the SD Sector changes.
But I can see how BC is stored to cover 16bit track numbers. For the moment, I'm only dealing with 8 bits... but I should update my BIOS to conform to this standard.


>And boy, are there some bizarre sector address calculation routines out there. I should know.

I'm not going to ask.

But Thank you very much for all your wonderful insight and time to answer my questions. It's very much appreciated.

Regards,
Josh Bensadon