View Full Version : Blocking and deblocking

February 16th, 2018, 03:56 PM
I've done some reading and it sounds like 2.2 required you to do the blocking/deblocking in the BIOS, but 3.1 handles it in BDOS (although it looks like it would allow you to do it in the BIOS if you really wanted to).

Some questions about blocking/deblocking. Does this merely mean if you have say a 512 byte sector, that you have a memory buffer set aside for the 512 bytes. Would your code then be smart enough to know if it has the 128 byte record in memory or not? Almost like a disk cache? For example, if you read the first 128 byte record and the BIOS loads a 512 byte block. Then if it asks for the next record, it would just grab the second 128 bytes from that 512? And so on? Is that right?

What about writing? Would you start a new block and wait to see if the other 3 records are written so you can avoid doing a read/modify/write? How would you know ahead of time whether you should read the sector in and then begin to apply changed 128 byte records to it?

I've tried to read some things about this, but I haven't found them all that useful in understanding it fully. BDOS providing 0=normal sector write, 1=write to directory, 2=write to first sector of new data block. Does 2 mean don't read the block in at all because BDOS knows all 4 parts are new. How could it if it isn't privy to the BIOS block size? I don't see the logic in how this 0/1/2 gives the BIOS any real hints on what to do.

Also, I saw that the FLUSH command flushes file changes because of the blocking/deblocking. Presumably it had no purpose beyond that. Again, if you write record 0 and record 2, does it have to read records 1 and 3 in first, then change it, then rewrite it? How does it do that with one 512 byte buffer?

February 16th, 2018, 04:50 PM
It's been a long time since I wrote these parts of a 2.2 BIOS. I was somewhat involved in the development of this 2.2 feature, but it started out as a patch to CP/M 1.4 that passed some extra information to the BIOS during WRITE in order to make better decisions.

The idea is that the BDOS knows if it is writing new records to a file, in which case there is no need to back-fill the sector buffer. Of course, letting CP/M 3 handle it all is the best, especially since BDOS3 also handles the buffers and can do an LRU scheme.

No, BDOS2.2 does not know the physical sector size, but it does know the file allocation block size, and it knows when it is writing to the first record of an unallocated block. As I recall, this "hint" did not completely eliminate the need for special handling in the BIOS, but it gave you a better idea of what the BDOS (and user program) were doing so that you can make better decisions. The BIOS does know the file allocation geometry, since it provides that to the BDOS, so it is capable of make some optimizations from that parameter.

What I recall doing, and have seen in other vendor's BIOSs too, is that you have a sector buffer and some parameters to remember what track, side, and sector it is. You then keep the sector data valid until you have to operate on a different sector. You could keep two buffers, for example, and if you know that some I/O is for the directory then you can optimize and not disturb the data buffer.

February 16th, 2018, 05:06 PM
Referencing your question on the other thread, CP/M 3 BDOS blocking/deblocking was actually a major improvement. As stated, the BDOS has much more information from which to make deblocking decisions. Coupled with buffer management, and it made the BIOS a great deal simpler and the system performed better. The CP/M 3 DPB informs the BDOS what the physical sector size is, so it has the information it needs. BDOS3 also adds the "multi record I/O" feature, which means that it can completely eliminate any buffering of the disk I/O in cases where a program is doing a large chunk of contiguous I/O. For example, when PIP is doing a copy the BDOS only uses a buffer for the last part of the I/O - if it is not a full sector.

February 16th, 2018, 05:10 PM
Yes, all of that. If you're talking about physical sectors larger than 128 bytes, you do have to implement blocking and deblocking in the BIOS--there's no other place to do it.

When I started doing this with CP/M 1.4, it was brute-force--if a write was issued, you had to read the physical sector that the 128-byte logical sector was present in beforehand, insert the 128 byte sector. You held the sector data around until either another write to the same physical sector occurred or a different physical sector was referenced, in which case, you wrote out the saved physical sector. On both warm and cold boots you have to make sure that any pending write has been flushed to disk. Similarly, if a different drive is selected, you have to flush and invalidate the buffer.

CP/M 2.0 helped eliminate a few extra writes and also improved reliability by passing a value in register C on the "Write Disk" BIOS call. C=0 says you're dealing with a "normal" sector write, so you'll have to read the physical sector before inserting the 128-byte logical sector. C=1 says you're writing to the directory, so you'll want to flush your write immediately to disk to avoid corruption. C=2 says that you're writing to a previously unallocated area, so you don't need to read the sector beforehand. You can actually get a certain performance boost by delaying the flush-to-disk until absolutely necessary. Even better, if you have an interrupt-driven disk BIOS, you can post the write and return immediately to the caller, waiting for completion only when another disk operation is desired.

If you've got the memory, by far, the greatest boost in performance is by having a full-track buffer and filling the whole thing the moment the track is accessed and flushing only when needed. Big sequential accesses run like the wind. Of course, the cost is the memory buffer size, which, if you have bankswitching memory, is no big deal.

February 16th, 2018, 06:44 PM
Does CP/M issue multiple READS or WRITES after selecting a track/sector, or does it always select again:


February 16th, 2018, 06:52 PM
I'm pretty sure the BDOS calls those routines (plus SETDMA) each read/write. I have seen it spelled out in one of the documents. Not sure if anyone wrote utilities that do otherwise. Generally, SETDMA, SETTRK and SETSEC are made very fast/simple and just store values for later use by READ/WRITE.

February 16th, 2018, 06:56 PM
You'll at least get a SETDMA and a SETSEC as far as I can recall. Not sure about the SETTRK.

But durgadas311's point is that you just stash the values for a subsequent operation--you don't do anything physical until you actually get a read or write call. That is, you don't seek to the track in a SETTRK until you're ready to read or write. Many folks don't even do anything with a HOME call--just set the current track number to 0.

February 20th, 2018, 07:44 AM
One issue I've run into is that numerous programs call the BIOS disk I/O routines directly and do not set register C. Therefore, the BIOS cannot assume the blocking "hint" passed in register C is valid.

I've written numerous track buffered BIOS's over the year and agree that it is by far the best way to implement blocking/deblocking. I have found performance to be 20%-70% faster than non buffered versions across a wide variety of different activities. And full write verify is easily added with just a small performance penalty.

The comments from Chuck and others regarding SETSEC, SETTRK, SETDMA, and HOME are correct. Let these entry points simply save the value passed. When the actual READ or WRITE request comes in, use whatever value your BIOS has last saved from preceding SETxxx calls.