.he .bp odd .mt 5 .mb 6 .pl 66 .ll 65 .po 10 .hm 2 .fm 2 .ft All Information Presented Here is Proprietary to Digital Research .sp 3 .sh .ce 2 .tc 5 Creating a BIOS Section 5 .SP .sh Creating a BIOS .sp 3 .sh 5.1 Overview .tc 5.1 Overview .pp The BIOS provides a standard interface to the physical input/output devices in your system. The BIOS interface is defined by the functions described in Section 4. Those functions, taken together, constitute a model of the hardware environment. Each BIOS is responsible for mapping that model onto the real hardware. .ix BIOS, creating .ix BIOS interface .pp In addition, the BIOS contains disk definition tables which define the characteristics of the disk devices which are present, and provides some storage for use by the BDOS in maintaining disk directory information. .pp Section 4 describes the functions which must be performed by the BIOS, and the external interface to those functions. This Section contains additional information describing the structure and significance of the disk definition tables and information about sector blocking and deblocking. Careful choices of disk parameters and disk buffering methods are necessary if you are to achieve the best possible performance from CP/M-8000. Therefore, this section should be read thoroughly before writing a custom BIOS. .sp 2 .sh 5.2 Disk Definition Tables .he CP/M-8000 System Guide 5.2 Disk Definition Tables .tc 5.2 Disk Definition Tables .ix disk definition tables .ix CP/M-8000 configuration .pp As in other CP/M systems, CP/M-8000 uses a set of tables to define disk device characteristics. This section describes each of these tables and discusses choices of certain parameters. .bp .sh 5.2.1 Disk Parameter Header .tc 5.2.1 Disk Parameter Header .ix Disk Parameter Header (DPH) .ix scratchpad area .pp Each disk drive has an associated 26-byte Disk Parameter Header (DPH) which both contains information about the disk drive and provides a scratchpad area for certain BDOS operations. Each drive must have its own unique DPH. The format of a Disk Parameter Header is shown in Figure 5-1. .sp 3 .ce 100 .nf XLT 0000 0000 0000 DIRBUF DPB CSV ALV .sp 32b 16b 16b 16b 32b 32b 32b 32b .sp .sh Figure 5-1. Disk Parameter Header .sp 2 .ce 0 .fi .ix word (16-bit) value .ix longword (32-bit) value .pp Each element of the DPH is either a word (16-bit) or longword (32-bit) value. The meanings of the Disk Parameter Header (DPH) elements are given in Table 5-1. .sp 2 .ce .sh Table 5-1. Disk Parameter Header Elements .qs .ix Disk Parameter Header elements .sp .nf Element Description .sp .fi .ll 62 .in 15 .ti -10 XLT Address of the logical-to-physical sector translation table, if used for this particular drive, or the value 0 if there is no translation table for this drive (i.e, the physical and logical sector numbers are the same). Disk drives with identical sector translation may share the same translate table. The sector translation table is described in Section 5.2.2. .ix XLT .sp .ti -10 0000 Three scratchpad words for use within the BDOS. .sp .ix scratchpad words .ix 0000 .ti -10 DIRBUF Address of a 128-byte scratchpad area for directory operations within BDOS. All DPHs address the same scratchpad area. .ix DIRBUF .sp .ti -10 DPB Address of a disk parameter block for this drive. Drives with identical disk characteristics may address the same disk parameter block. .ix DPB .bp .ll 65 .in 0 .ce .sh Table 5-1. (continued) .sp .nf Element Description .fi .sp .ll 62 .in 15 .ti -10 CSV Address of a checksum vector. The BDOS uses this area to maintain a vector of directory checksums for the disk. These checksums are used in detecting when the disk in a drive has been changed. If the disk is not removable, then it is not necessary to have a checksum vector. Each DPH must point to a unique checksum vector. The checksum vector should contain 1 byte for every four directory entries (or 128 bytes of directory). In other words: length (CSV) = (DRM+1) / 4. (DRM is discussed in Section 5.2.3.) .ix CSV .ix checksum vector .sp .ti -10 ALV Address of a scratchpad area used by the BDOS to keep disk storage allocation information. The area must be different for each DPH. There must be 1 bit for each allocation block on the drive, requiring the following: length (ALV) = (DSM/8) + 1. (DSM is discussed below.) .ix ALV .ix Disk Parameter Header elements .in 0 .ll 65 .sp 3 .sh 5.2.2 Sector Translate Table .tc 5.2.2 Sector Translate Table .pp Sector translation in CP/M-8000 is a method of logically renumbering the sectors on each disk track to improve disk I/O performance. A frequent situation is that a program needs to access disk sectors sequentially. However, in reading sectors sequentially, most programs lose a full disk revolution between sectors because there is not enough time between adjacent sectors to begin a new disk operation. To alleviate this problem, the traditional CP/M solution is to create a logical sector numbering scheme in which logically sequential sectors are physically separated. Thus, between two logically contiguous sectors, there is a several sector rotational delay. The sector translate table defines the logical-to-physical mapping in use for a particular drive, if a mapping is used. .ix logical sector numbering .ix mapping, logical to physical .ix rotational latency .pp Sector translate tables are used only within the BIOS. Thus the table may have any convenient format. (Although the BDOS is aware of the sector translate table, its only interaction with the table is to get the address of the sector translate table from the DPH and to pass that address to the Sector Translate Function of the BIOS.) The most common form for a sector translate table is an n-byte (or n-word) array of physical sector numbers, where n is the number of sectors per disk track. Indexing into the table with the logical sector number yields the corresponding physical sector number. .ix sector translate table .pp Although you may choose any convenient logical-to-physical mapping, there is a nearly universal mapping used in the CP/M community for single-sided, single-density, 8-inch diskettes. That mapping is shown in Figure 5-2. Because your choice of mapping affects diskette compatibility between different systems, the mapping of Figure 5-2 is strongly recommended. .sp 3 .nf .sp Logical Sector 0 1 2 3 4 5 6 7 8 9 10 11 12 Physical Sector 1 7 13 19 25 5 11 17 23 3 9 15 21 .sp Logical Sector 13 14 15 16 17 18 19 20 21 22 23 24 25 Physical Sector 2 8 14 20 26 6 12 18 24 4 10 16 22 .sp 2 .ce .sh Figure 5-2. Sample Sector Translate Table .fi .sp 2 .sh 5.2.3 Disk Parameter Block .tc 5.2.3 Disk Parameter Block .pp A Disk Parameter Block (DPB) defines several characteristics associated with a particular disk drive. Among them are the size of the drive, the number of sectors per track, the amount of directory space, and others. .ix Disk Parameter Block (DPB) .pp A Disk Parameter Block can be used in one or more DPH's if the disks are identical in definition. A discussion of the fields of the DPB follows the format description. The format of the DPB is shown in Figure 5-3. .cp 6 .sp 2 .nf .sp SPT BSH BLM EXM 0 DSM DRM Reserved CKS OFF .sp 16b 8b 8b 8b 8b 16b 16b 16b 16b 16b .sp .ce .sh Figure 5-3. Disk Parameter Block .sp 2 .fi .sp Each field is a word (16 bit) or a byte (8 bit) value. The description of each field is given in Table 5-2. .ix byte (8 bit) value .ix word (16 bit) value .sp 2 .ix Disk Parameter Block fields .ce .sh Table 5-2. Disk Parameter Block Fields .sp .nf Field Definition .fi .ll 62 .in 15 .sp .ti -10 SPT Number of 128-byte logical sectors per track. .ix SPT .sp .ti -10 BSH The block shift factor, determined by the data block allocation size, as shown in Table 5-3. .ix BSH .ix Block Shift Factor .bp .ce .ll 65 .in 0 .sh Table 5-2. (continued) .sp .nf Field Definition .sp .fi .in 15 .ll 62 .ti -10 BLM The block mask which is determined by the data block allocation size, as shown in Table 5-3. .ix BLM .ix Block Mask .sp .ti -10 EXM The extent mask, determined by the data block allocation size and the number of disk blocks, as shown in Table 5-4. .ix BLM .ix Extent Mask .sp .ti -10 0 Reserved byte. .sp .ti -10 DSM Determines the total storage capacity of the disk drive and is the number of the last block, counting from 0. That is, the disk contains DSM+1 blocks. .ix DSM .ix disk drive, total storage capacity .sp .ti -10 DRM Determines the total number of directory entries which can be stored on this drive. DRM is the number of the last directory entry, counting from 0. That is, the disk contains DRM+1 directory entries. Each directory entry requires 32 bytes, and for maximum efficiency, the value of DRM should be chosen so that the directory entries exactly fill an integral number of allocation units. .ix DRM .sp .ti -10 CKS The size of the directory check vector, which is zero if the disk is permanently mounted, or length (CSV) = (DRM) / 4 + 1 for removable media. .ix CKS .ix directory check vector .sp .ti -10 OFF The number of reserved tracks at the beginning of a logical disk. This is the number of the track on which the directory begins. .ix OFF .ix reserved tracks, number of .ll 65 .in 0 .sp .pp To choose appropriate values for the Disk Parameter Block elements, you must understand how disk space is organized in CP/M-8000. A CP/M-8000 disk has two major areas: the boot or system tracks, and the file system tracks. The boot tracks are usually used to hold a machine-dependent bootstrap loader for the operating system. They consist of tracks 0 to OFF-1. Zero is a legal value for OFF, and in that case, there are no boot tracks. The usual value of OFF for 8-inch floppy disks is two. .ix file system tracks .ix boot tracks .ix Disk Parameter Blocks .ix bootstrap loader, machine dependent .pp The tracks after the boot tracks (beginning with track number OFF) are used for the disk directory and disk files. Disk space in this area is grouped into units called allocation units or blocks. The block size for a particular disk is a constant, called BLS. BLS may take on any one of these values: 1024, 2048, 4096, 8192, or 16384 bytes. No other values for BLS are allowed. (Note that BLS does not appear explicitly in any BIOS table. However, it determines the values of a number of other parameters.) The DSM field in the Disk Parameter Block is one less than the number of blocks on the disk. Space is allocated to a file or to the directory in whole blocks. No fraction of a block can be allocated. block size .ix BLS .ix DSM .pp The choice of BLS is very important, because it effects the efficiency of disk space utilization, and because for any disk size there is a minimum value of BLS that allows the entire disk to be used. Each block on the disk has a block number ranging from 0 to DSM. The largest block number allowed is 32767. Therefore, the largest number of bytes that can be addressed in the file system space is 32768 * BLS. Because the largest allowable value for BLS is 16384, the biggest disk that can be accessed by CP/M-8000 is 16384*32768 = 512 Mbytes. .ix block number, largest allowed .pp Each directory entry may contain either 8 block numbers (if DSM >= 256) or 16 block numbers (if DSM < 256). Each file needs enough directory entries to hold the block numbers of all blocks allocated to the file. Thus a large value for BLS implies that fewer directory entries are needed. Since fewer directory entries are used, the directory search time is decreased. .pp The disadvantage of a large value for BLS is that since files are allocated BLS bytes at a time, there is potentially a large unused portion of a block at the end of the file. If there are many small files on a disk, the waste can be very significant. .pp The BSH and BLM parameters in the DPB are functions of BLS. Once you have chosen BLS, you should use Table 5-3 to determine BSH and BLM. The EXM parameter of the DPB is a function of BLS and DSM. You should use Table 5-4 to find the value of EXM for your disk. .ix ESM .sp 3 .nf .sh Table 5-3. BSH and BLM Values .sp BLS BSH BLM 1024 3 7 2048 4 15 4096 5 31 8192 6 63 16384 7 127 .in 0 .fi .bp .sh Table 5-4. EXM Values .sp .nf BLS DSM <= 255 DSM > 255 .sp 1024 0 N/A 2048 1 0 4096 3 1 8192 7 3 16384 15 7 .in 0 .fi .ll 65 .sp .pp The DRM entry in the DPB is one less than the total number of directory entries. DRM should be chosen large enough so that you do not run out of directory entries before running out of disk space. It is not possible to give an exact rule for determining DRM, since the number of directory entries needed will depend on the number and sizes of the files present on the disk. .pp The CKS entry in the DPB is the number of bytes in the CSV (checksum vector) which was pointed to by the DPH. If the disk is not removable, a checksum vector is not needed, and this value may be zero. .sp 2 .sh 5.3 Disk Blocking System Guide .tc 5.3 Disk Blocking Guide .he CP/M-8000 System Guide 5.3 Disk Blocking .ix sector, 128-byte .pp When the BDOS does a disk read or write operation using the BIOS, the unit of information read or written is a 128-byte sector. This may or may not correspond to the actual physical sector size of the disk. If not, the BIOS must implement a method of representing the 128-byte sectors used by CP/M-8000 on the actual device. Usually if the physical sectors are not 128 bytes long, they will be some multiple of 128 bytes. Thus, one physical sector can hold some integer number of 128-byte CP/M sectors. In this case, any disk I/O will actually consist of transferring several CP/M sectors at once. .pp It might also be desirable to do disk I/O in units of several 128-byte sectors in order to increase disk throughput by decreasing rotational latency. (Rotational latency is the average time it takes for the desired position on a disk to rotate around to the read/write head. Generally this averages 1/2 disk revolution per transfer.) Since a great deal of disk I/O is sequential, rotational latency can be greatly reduced by reading several sectors at a time, and saving them for future use. .ix rotational latency .ix read/write head .pp In both the cases above, the point of interest is that physical I/O occurs in units larger than the expected sector size of 128 bytes. Some of the problems in doing disk I/O in this manner are discussed below. .bp .sh 5.3.1 A Simple Approach .pp This section presents a simple approach to handling a physical sector size larger than the logical sector size. The method discussed in this section is not recommended for use in a real BIOS. Rather, it is given as a starting point for refinements discussed in the following sections. Its simplicity also makes it a logical choice for a first BIOS on new hardware. However, the disk throughput that you can achieve with this method is poor, and the refinements discussed later give dramatic improvements. .ix disk throughput .pp Probably the easiest method for handling a physical sector size which is a multiple of 128 bytes is to have a single buffer the size of the physical sector internal to the BIOS. Then, when a disk read is to be done, the physical sector containing the desired 128-byte logical sector is read into the buffer, and the appropriate 128 bytes are copied to the DMA address. Writing is a little more complicated. You only want to put data into a 128-byte portion of the physical sector, but you can only write a whole physical sector. Therefore, you must first read the physical sector into the BIOS's buffer; copy the 128 bytes of output data into the proper 128-byte piece of the physical sector in the buffer; and finally write the entire physical sector back to disk. .sp .sh Note: \c .qs this operation involves two rotational latency delays in addition to the time needed to copy the 128 bytes of data. In fact, the second rotational wait is probably nearly a full disk revolution, since the copying is usually much faster than a disk revolution. .sp 2 .sh 5.3.2 Some Refinements .tc 5.3.2 Some Refinements .ix disk access, sequential .pp There are some easy things that can be done to the algorithm of Section 5.2.1 to improve its performance. The first is based on the fact that disk accesses are usually done sequentially. Thus, if data from a certain physical sector is needed, it is likely that another piece of that sector will be needed on the next disk operation. To take advantage of this fact, the BIOS can keep information with its physical sector buffer as to which disk, track, and physical sector (if any) is represented in the buffer. Then, when reading, the BIOS need only do physical disk reads when the information needed is not in the buffer. .pp On writes, the BIOS still needs to preread the physical sector for the same reasons discussed in Section 5.2.1, but once the physical sector is in the buffer, subsequent writes into that physical sector do not require additional prereads. An additional saving of disk accesses can be gained by not writing the sector to the disk until absolutely necessary. The conditions under which the physical sector must be written are discussed in Section 5.3.4. .ix physical sector .bp .sh 5.3.3 Track Buffering .tc 5.3.3 Track Buffering .pp Track buffering is a special case of disk buffering where the I/O is done a full track at a time. When sufficient memory for several full track buffers is available, this method is quite good. The method is essentially the same as discussed in Section 5.3.2, but there are some interesting features. First, transferring an entire track is much more efficient than transferring a single sector. The rotational latency is incurred only once for the entire track, whereas if the track is transferred one sector at a time, the rotational latency occurs once per sector. On a typical diskette with 26 sectors per track, rotating at 6 revolutions per second, the difference in rotational latency per track is about 2 seconds versus a twelfth of a second. Of course, in applications where the disk is accessed purely randomly, there is no advantage because there is a low probability that more than one sector will be used from a given track. However, such applications are extremely rare. .ix rotational latency .sp 2 .sh 5.3.4 LRU Replacement .tc 5.3.4 LRU Replacement .pp With any method of disk buffering using more than one buffer, it is necessary to have some algorithm for managing the buffers. That is, when should buffers be filled, and when should they be written back to disk. The first question is simple, a buffer should be filled when there is a request for a disk sector that is not presently in memory. The second issue, when to write a buffer back to disk, is more complicated. .ix buffer, writing to disk .pp Generally, it is desirable to defer writing a buffer until it becomes necessary. Thus, several transfers can be done to a buffer for the cost of only one disk access, two accesses if the buffer had to be preread. However, there are several reasons why buffers must be written. The following list describes the reasons: .sp 2 .in 8 .ti -3 1) A BIOS Write operation with mode=1 (write to directory sector). To maintain the integrity of CP/M-8000's file system, it is very important that directory information on the disk is kept up to date. Therefore, all directory writes should be performed immediately. .ix BIOS write operation .sp .ti -3 2) A BIOS Flush Buffers operation. This BIOS function is explicitly intended to force all disk buffers to be written. After performing a Flush Buffers, it is safe to remove a disk from its drive. .ix BIOS flush buffers operation .sp .ti -3 3) A disk buffer is needed, but all buffers are full. Therefore some buffer must be emptied to make it available for reuse. .sp .ti -3 4) A Warm Boot occurs. This is similar to number 2 above. .ix warm boot .ix boot, warm .sp .in 0 .pp Case three above is the only one in which the BIOS writer has any discretion as to which buffer should be written. Probably the best strategy is to write out the buffer which has been least recently used. The fact that an area of disk has not been accessed for some time is a fairly good indication that it will not be needed again soon. .ix LRU buffers .sp 2 .sh 5.3.5 The New Block Flag .tc The New Block Flag .pp As explained in Section 5.2.2, the BDOS allocates disk space to files in blocks of BLS bytes. When such a block is first allocated to a file, the information previously in that block need not be preserved. To enable the BIOS to take advantage of this fact, the BDOS uses a special parameter in calling the BIOS Write Function. If register D1.W contains the value 2 on a BIOS Write call, then the write being done is to the first sector of a newly allocated disk block. Therefore, the BIOS need not preread any sector of that block. If the BIOS does disk buffering in units of BLS bytes, it can simply mark any free buffer as corresponding to the disk address specified in this write, because the contents of the newly allocated block are not important. If the BIOS uses a buffer size other than BLS, then the algorithm for taking full advantage of this information is more complicated. .ix BLS bytes .pp This information is extremely valuable in reducing disk delays. Consider the case where one file is read sequentially and copied to a newly created file. Without the information about newly allocated disk blocks, every physical write would require a preread. With the information, no physical write requires a preread. Thus, the number of physical disk operations is reduced by one third. .sp 2 .ce End of Section 5 .nx six