.bp 13
.tc    6.6  The BIOS Entry Points
.he CP/M Operating System Manual               6.6  BIOS Entry Points
.sh
6.6  The BIOS Entry Points
.qs
.pp 5
The entry points into the BIOS from the cold start loader and 
BDOS are detailed below.  Entry to the BIOS is through a jump 
vector located at 4A00H+b, as shown below.  See Appendixes A and 
B.  The jump vector is a sequence of 17 jump 
instructions that send program control to the individual BIOS 
subroutines.  The BIOS subroutines might be empty for certain 
functions (they might contain a single RET operation) 
during reconfiguration of CP/M, but the entries must be present 
in the jump vector.
.pp
The jump vector at 4A00H+b takes the form shown below, where the 
individual jump addresses are given to the left:
.mb 4
.fm 1
.mt 4
.hm 1
.sp 2
.nf
.in 5
4A00H+b      JMP BOOT       ;ARRIVE HERE FROM COLD
                             START LOAD
.sp
4A03H+b      JMP WBOOT      ;ARRIVE HERE FOR WARM START

4A06H+b      JMP CONST      ;CHECK FOR CONSOLE CHAR
                             READY

4A09H+b      JMP CONIN      ;READ CONSOLE CHARACTER IN

4A0CH+b      JMP CONOUT     ;WRITE CONSOLE CHARACTER
                             OUT

4A0FH+b      JMP LIST       ;WRITE LISTING CHARACTER OUT

4A12H+b      JMP PUNCH      ;WRITE CHARACTER TO PUNCH
                             DEVICE

4A15H+b      JMP READER     ;READ READER DEVICE

4A18H+b      JMP HOME       ;MOVE TO TRACK 00 ON
                             SELECTED DISK

4A1BH+b      JMP SELDSK     ;SELECT DISK DRIVE

4A1EH+b      JMP SETTRK     ;SET TRACK NUMBER

4A21H+b      JMP SETSEC     ;SET SECTOR NUMBER

4A24H+b      JMP SETDMA     ;SET DMA ADDRESS

4A27H+b      JMP READ       ;READ SELECTED SECTOR

4A2AH+b      JMP WRITE      ;WRITE SELECTED SECTOR

4A2DH+b      JMP LISTST     ;RETURN LIST STATUS

4A30H+b      JMP SECTRAN    ;SECTOR TRANSLATE
                             SUBROUTINE
.fi
.in 0
.sp 2
.sh
                 Listing 6-2.  BIOS Entry Points
.pp
Each jump address corresponds to a particular subroutine that performs the
specific function, as outlined below.  There are three major 
divisions in the jump table:  the system reinitialization, 
which results from calls on BOOT and WBOOT; simple character I/O, 
performed by calls on CONST, CONIN, CONOUT, LIST, PUNCH, READER, 
and LISTST; and disk I/O, performed by calls on HOME, SELDSK, 
SETTRK, SETSEC, SETDMA, READ, WRITE, and SECTRAN.
.pp
All simple character I/O operations are assumed to be performed 
in ASCII, upper- and lower-case, with high-order (parity bit) set 
to zero.  An end-of-file condition for an input device is given 
by an ASCII CTRL-Z (1AH).  Peripheral devices are seen by CP/M as 
logical devices and are assigned to physical devices within the 
BIOS.
.pp
To operate, the BDOS needs only the CONST, CONIN, and CONOUT 
subroutines.  LIST, PUNCH, and READER can be used by PIP, but not 
the BDOS.  Further, the LISTST entry is currently used only by 
DESPOOL, the print spooling utility.  Thus, the initial version 
of CBIOS can have empty subroutines for the remaining ASCII 
devices.
.pp
The following list describes the characteristics of each device.
.sp 2
.in 5
.ti -2
o CONSOLE is the principal interactive console that communicates with the
operator and it is accessed through CONST, CONIN, and CONOUT.  Typically, the
CONSOLE is a device such as a CRT or teletype.
.sp
.ti -2
o LIST is the principal listing device.  If it exists on the user's system,
it is usually a hard-copy device, such as a printer or teletype.
.sp
.ti -2
o PUNCH is the principal tape punching device.  If it exists, it is normally a
high-speed paper tape punch or teletype.
.sp
.ti -2
o READER is the principal tape reading device, such as a simple optical
reader or teletype.
.fi
.in 0
.sp
.pp
A single peripheral can be assigned as the LIST, PUNCH, and 
READER device simultaneously.  If no peripheral device is 
assigned as the LIST, PUNCH, or READER device, the CBIOS 
gives an appropriate error message so that the 
system does not hang if the device is accessed by PIP or some 
other user program.  Alternately, the PUNCH and LIST routines can 
just simply return, and the READER routine can return with a 1AH 
(CTRL-Z) in register A to indicate immediate end-of-file.
.pp
For added flexibility, you can optionally implement the 
IOBYTE function, which allows reassignment of physical devices.
The IOBYTE function creates a mapping of logical-to-physical 
devices that can be altered during CP/M processing, 
see the STAT command in Section 1.6.1.
.pp
The definition of the IOBYTE function corresponds to the Intel 
standard as follows:  a single location in memory, currently 
location 0003H, is maintained, called IOBYTE, which defines the 
logical-to-physical device mapping that is in effect at a 
particular time.  The mapping is performed by splitting the 
IOBYTE into four distinct fields of two bits each, called the 
CONSOLE, READER, PUNCH, and LIST fields, as shown in the 
following figure.
.sp 2
.nf
                      most significant      least significant
.sp
    IOBYTE AT 003H    LIST       PUNCH      READER     CONSOLE
.sp
                      bits 6,7  bits 4,5  bits 2,3   bits 0,1
.fi
.sp 2
.sh
                   Figure 6-1.  IOBYTE Fields
.sp 2
.pp
The value in each field can be in the range 0-3, defining the 
assigned source or destination of each logical device.  Table 6-4
gives the values that can be assigned to each field.
.sp 2
.sh
.nf
                 Table 6-4. IOBYTE Field Values
.sp
        Value                   Meaning
.sp
                    CONSOLE field (bits 0,1)
.sp
         0     console is assigned to the console printer
               device (TTY:)
         1     console is assigned to the CRT device (CRT:)
         2     batch mode:  use the READER as the CONSOLE input,
               and the LIST device as the CONSOLE output (BAT:)
         3     user-defined console device (UC1:)
.sp
.mb 4
.fm 1
.mt 4
.hm 1
                     READER field (bits 2,3)
.sp
         0     READER is the teletype device (TTY:)
         1     READER is the high speed reader device (PTR:)
         2     user-defined reader #1 (UR1:)
         3     user-defined reader #2 (UR2:)
.sp
                     PUNCH field (bits 4,5)
.sp
         0     PUNCH is the teletype device (TTY:)
         1     PUNCH is the high speed punch device (PTP:)
         2     user-defined punch #1 (UP1:)
         3     user-defined punch #2 (UP2:)
.sp
                      LIST field (bits 6,7)
.sp
         0     LIST is the teletype device (TTY:)
         1     LIST is the CRT device (CRT:)
         2     LIST is the line printer device (LPT:)
         3     user-defined list device (UL1:)
.fi
.bp
.pp
The implementation of the IOBYTE is optional and effects only the 
organization of the CBIOS.  No CP/M systems use the IOBYTE 
(although they tolerate the existence of the IOBYTE at location 
0003H) except for PIP, which allows access to the physical 
devices, and STAT, which allows logical-physical assignments to 
be make or displayed.  For more information see Section 1.  In 
any case the IOBYTE implementation should be omitted until the 
basic CBIOS is fully implemented and tested; then you should 
add the IOBYTE to increase the facilities.
.mb 6
.fm 2
.mt 5
.hm 2
.pp
Disk I/O is always performed through a sequence of calls on the 
various disk access subroutines that set up the disk number to 
access, the track and sector on a particular disk, and the Direct 
Memory Access (DMA) address involved in the I/O operation.  After 
all these parameters have been set up, a call is made to the READ 
or WRITE function to perform the actual I/O operation.
.pp
There is often a single call to SELDSK to select a disk drive, 
followed by a number of read or write operations to the selected 
disk before selecting another drive for subsequent operations.  
Similarly, there might be a single call to set the DMA address, 
followed by several calls that read or write from the selected 
DMA address before the DMA address is changed.  The track and 
sector subroutines are always called before the READ or WRITE 
operations are performed.
.pp
The READ and WRITE routines should perform several retries (10 is 
standard) before reporting the error condition to the BDOS.  If 
the error condition is returned to the BDOS, it reports the 
error to the user.  The HOME subroutine might or might not actually 
perform the track 00 seek, depending upon controller 
characteristics; the important point is that track 00 has been 
selected for the next operation and is often treated in exactly 
the same manner as SETTRK with a parameter of 00.
.pp
The following table describes the exact responsibilities of each 
BIOS entry point subroutine.
.sp 2
.sh
                  Table 6-5.  BIOS Entry Points
.sp
   Entry Point                    Function
.sp
.ll 60
.in 15
.ti -9
BOOT     The BOOT entry point gets control from the cold start loader and is
responsible for basic system initialization, including sending a sign-on
message, which can be omitted in the first version.  If the IOBYTE function
is implemented, it must be set at this point.  The various system parameters
that are set by the WBOOT entry point must be initialized, and control is
transferred to the CCP at 3400+b for further processing.  Note that register
C must be set to zero to select drive A.
.in 0
.bp
.sh
                     Table 6-5.  (continued)
.sp
   Entry Point                    Function
.sp
.in 15
.ti -9
WBOOT    The WBOOT entry point gets control when a warm start occurs.  A warm
start is performed whenever a user program branches to location 0000H, or
when the CPU is reset from the front panel.  The CP/M system must be loaded
from the first two tracks of drive A up to, but not including, the BIOS, or
CBIOS, if the user has completed the patch.  System parameters must be
initialized as follows:
.sp
.in 32
.ti -17
location 0,1,2   Set to JMP WBOOT for warm starts (000H: JMP 4A03H+b)
.sp
.ti -17
location 3       Set initial value of IOBYTE, if implemented in the CBIOS
.sp
.ti -17
location 4       High nibble = current user no; low nibble = current drive
.sp
.ti -17
location 5,6,7   Set to JMP BDOS, which is the primary entry point to CP/M for
transient programs.  (0005H: JMP 3C06H+b)
.sp
.in 15
Refer to Section 6.9 for complete details of page zero use.
Upon completion of the initialization, the WBOOT program must branch to the
CCP at 3400H+b to restart the system.  Upon entry to the CCP, register C is
set to the drive to select after system initialization.  The WBOOT routine
should read location 4 in memory, verify that is a legal drive, and pass it
to the CCP in register C.
.sp
.ti -9
CONST    You should sample the status of the currently assigned console
device and return 0FFH in register A if a character is ready to read and 00H
in register A if no console characters are ready.
.sp
.ti -9
CONIN    The next console character is read into register A, and the parity
bit is set, high-order bit, to zero.  If no console character is ready, 
wait until a character is typed before returning.
.in 0
.bp
.sh
                     Table 6-5.  (continued)
.sp
   Entry Point                    Function
.sp
.in 15
.ti -9
CONOUT   The character is sent from register C to the console
output device.  The character is in ASCII, with high-order parity 
bit set to zero.  You might want to include a time-out on a 
line-feed or carriage return, if the console device requires some 
time interval at the end of the line (such as a TI Silent 700  
terminal).  You can filter out control characters that cause 
the console device to react in a strange way (CTRL-Z causes the 
Lear-Seigler terminal to clear the screen, for example).
.sp
.ti -9
LIST     The character is sent from register C to the currently
assigned listing device.  The character is in ASCII with zero 
parity bit.
.sp
.ti -9
PUNCH    The character is sent from register C to the currently
assigned punch device.  The character is in ASCII with zero 
parity.
.sp
.ti -9
READER   The next character is read from the currently assigned reader
device into register A with zero parity (high-order bit must be 
zero); an end-of-file condition is reported by returning an ASCII 
CTRL-Z(1AH).
.sp
.ti -9
HOME     The disk head of the currently selected disk
(initially disk A) is moved to the track 00 position.  If the controller
allows access to the track 0 flag from the drive, the head is 
stepped until the track 0 flag is detected.  If the controller 
does not support this feature, the HOME
call is translated into a call to SETTRK with a parameter of 0.
.sp
.ti -9
SELDSK   The disk drive given by register C is selected for further
operations, where register C contains 0 for drive A, 1 for drive B, and so
on up to 15 for drive P (the standard CP/M distribution version supports four
drives).  On each disk select, SELDSK must return in HL the base address of a
16-byte area, called the Disk Parameter Header, described in Section 6.10.
For standard floppy disk drives, the contents of the header and associated
tables do not change; thus, the program segment included in the sample CBIOS
performs this operation automatically.
.in 0
.bp
.sh
                     Table 6-5.  (continued)
.sp
   Entry Point                    Function
.sp
.in 15
If there is an attempt to select a
nonexistent drive, SELDSK returns HL=0000H as an error indicator.  
Although SELDSK must return the header address on each call, it is advisable
to postpone the physical disk select operation until an I/O function (seek,
read, or write) is actually performed, because disk selects often occur
without utimately performing any disk I/O, and many controllers unload
the head of the current disk before selecting the new drive.  This
causes an excessive amount of noise and disk wear.  The least significant bit
of register E is zero if this is the first occurrence of the drive select
since the last cold or warm start.
.sp
.ti -9
SETTRK   Register BC contains the track number for subsequent disk accesses
on the currently selected drive.  The sector number in BC is the same as the
number returned from the SECTRAN entry point.  You can choose to seek
the selected track at this time or delay the seek until the next read or
write actually occurs.  Register BC can take on values in the range 0-76
corresponding to valid track numbers for standard floppy disk drives and
0-65535 for nonstandard disk subsystems.
.sp
.ti -9
SETSEC   Register BC contains the sector number, 1 through 26, for subsequent
disk accesses on the currently selected drive.  The sector number in BC is
the same as the number returned from the SECTRAN entry point.  You can
choose to send this information to the controller at this point or delay
sector selection until a read or write operation occurs.
.mb 4
.fm 1
.sp
.ti -9
SETDMA   Register BC contains the DMA (Disk Memory Access) address for
subsequent read or write operations.  For example, if B = 00H and C = 80H
when SETDMA is called, all subsequent read operations read their data into
80H through 0FFH and all subsequent write operations get their
data from 80H through 0FFH, until the next call
to SETDMA occurs.  The initial DMA address is 
assumed to be 80H.  The controller need not
actually support Direct Memory Access.  If,
for example, all data transfers are through I/O
ports, the CBIOS that is constructed uses
the 128-byte area starting at the selected DMA
address for the memory buffer during the 
subsequent read or write operations.
.in 0
.bp
.sh
                     Table 6-5.  (continued)
.sp
   Entry Point                    Function
.sp
.in 15
.ti -9
READ     Assuming the drive has been selected, the track
has been set, and the DMA address has been 
specified, the READ subroutine attempts to
read one sector based upon these parameters
and returns the following error codes in 
register A:
.sp
0  no errors occurred
.sp
1  nonrecoverable error condition occurred
.sp
Currently, CP/M responds only to a zero or nonzero
value as the return code.  That is, if the
value in register A is 0, CP/M assumes that the 
disk operation was completed properly.  IF an
error occurs the CBIOS should attempt
at least 10 retries to see if the error is
recoverable.  When an error is reported the BDOS
prints the message BDOS ERR ONx:  BAD
SECTOR.  The operator then has the option of
pressing a carriage return to ignore the error, or
CTRL-C to abort.
.sp
.ti -9
WRITE    Data is written from the currently 
selected DMA address to the currently selected
drive, track, and sector.  For floppy disks, the 
data should be marked as nondeleted data to 
maintain compatibility with other CP/M systems.
The error codes given in the READ command are
returned in register A, with error recovery 
attempts as described above.
.mb 6
.fm 2
.sp
.ti -9
LISTST   You return the ready status of the list
device used by the DESPOOL program to improve
console response during its operation.  The 
value 00 is returned in A if the list device is 
not ready to accept a character and 0FFH if a 
character can be sent to the printer.  A 00 
value should be returned if LIST status is not
implemented.
.in 0
.bp
.sh
                     Table 6-5.  (continued)
.sp
   Entry Point                    Function
.sp
.in 15
.ti -9
SECTRAN  Logical-to-physical sector
translation is performed to improve the overall response of
CP/M.  Standard CP/M systems are shipped with a 
skew factor of 6, where six physical sectors are 
skipped between each logical read operation.
This skew factor allows enough time between
sectors for most programs to load their buffers
without missing the next sector.  In particular
computer systems that use fast processors,
memory, and disk subsystems, the skew factor might
be changed to improve overall response.
However, the user should maintain a single-density
IBM-compatible version of CP/M for
information transfer into and out of the
computer system, using a skew factor of 6.
.sp
In general, SECTRAN receives a logical sector
number relative to zero in BC and a translate
table address in DE.  The sector number is used
as an index into the translate table, with the
resulting physical sector number
in HL.  For standard systems, the table and
indexing code is provided in the CBIOS and
need not be changed.
.in 0
.ll 65
.sp 2
.tc    6.7  A Sample BIOS
.he CP/M Operating System Manual                   6.7  A Sample BIOS
.sh
6.7  A Sample BIOS
.qs
.pp
The program shown in Appendix B can serve as a basis for your 
first BIOS.  The simplest functions are assumed in this BIOS, so 
that you can enter it through a front panel, if absolutely 
necessary.  You must alter and insert code into the 
subroutines for CONST, CONIN, CONOUT, READ, WRITE, and WAITIO 
subroutines.  Storage is reserved for user-supplied code in these 
regions.  The scratch area reserved in page zero (see Section 
6.9) for the BIOS is used in this program, so that it could be 
implemented in ROM, if desired.
.pp
Once operational, this skeletal version can be enhanced to print 
the initial sign-on message and perform better error recovery.  
The subroutines for LIST, PUNCH, and READER can be filled out and 
the IOBYTE function can be implemented.
.sp 2
.tc    6.8  A Sample Cold Start Loader
.he CP/M Operating System Manual      6.8  A Sample Cold Start Loader
.sh
6.8  A Sample Cold Start Loader
.qs
.pp
The program shown in Appendix E can serve as a basis for a cold 
start loader.  The disk read function must be supplied by the 
user, and the program must be loaded somehow starting at location 
0000.  Space is reserved for the patch code so that the total 
amount of storage required for the cold start loader is 128 
bytes.
.pp
Eventually, you might want to get this 
loader onto the first disk sector (track 0, sector 1) and cause 
the controller to load it into memory automatically upon system 
start up.  Alternatively, the cold start loader can be placed 
into ROM, and above the CP/M system.  In this case, it is 
necessary to originate the program at a higher address and key in 
a jump instruction at system start up that branches to the 
loader.  Subsequent warm starts do not require this key-in 
operation, because the entry point WBOOT gets control, thus bringing 
the system in from disk automatically.  The skeletal cold start 
loader has minimal error recovery, which might be enhanced in later 
versions.
.sp 2
.tc    6.9  Reserved Locations in Page Zero
.he CP/M Operating System Manual 6.9  Reserved Locations in Page Zero
.sh
6.9  Reserved Locations in Page Zero
.qs
.pp
Main memory page zero, between locations 00H and 0FFH, contains 
several segments of code and data that are used during CP/M 
processing.  The code and data areas are given in the following table.
.sp 2
.sh
           Table 6-6.  Reserved Locations in Page Zero
.sp
.nf
     Locations                       Contents
.fi
.sp
.ll 60
.in 22
.ti -17
000H-0002H       Contains a jump instruction to the warm start entry location
4A03H+b.  This allows a simple programmed restart (JMP 0000H) or manual
restart from the front panel.
.sp
.ti -17
0003H-0003H      Contains the Intel standard IOBYTE is optionally
included in the user's CBIOS (refer to Section 6.6).
.sp
.ti -17
0004H-0004H      Current default drive number (0=A,...,15=P).
.sp
.ti -17
0005H-0007H      Contains a jump instruction to the BDOS and serves two
purposes:  JMP 0005H provides the primary entry point to the BDOS, as
described in Chapter 5, and LHLD 0006H brings the address field of the
instruction to the HL register pair.  This value is the lowest address in
memory used by CP/M, assuming the CCP is being overlaid.  The DDT program
changes the address field to reflect the reduced memory size in debug mode.
.sp
.ti -17
0008H-0027H      Interrupt locations 1 through 5 not used.
.sp
.ti -17
0030H-0037H      Interrupt location 6 (not currently used) is reserved.
.in 0
.bp
.sh
                     Table 6-6.  (continued)
.sp
.nf
     Locations                       Contents
.fi
.sp
.in 22
.ti -17
0038H-003AH      Restart 7; contains a jump instruction into the DDT or SID
program when running in debug mode for programmed breakpoints, but is not
otherwise used by CP/M.
.sp
.ti -17
003BH-003FH      Not currently used; reserved.
.sp
.ti -17
0040H-004FH      A 16-byte area reserved for scratch by CBIOS, but is not
used for any purpose in the distribution version of CP/M.
.sp
.ti -17
0050H-005BH      Not currently used; reserved.
.sp
.ti -17
005CH-007CH      Default File Control Block produced for a transient
program by the CCP.
.sp
.ti -17
007DH-007FH      Optional default random record position.
.sp
.ti -17
0080H-00FFH      Default 128-byte disk buffer, also filled with the
command line when a transient is loaded under the CCP.
.in 0
.ll 65
.mb 4
.fm 1
.sp
.pp
This information is set up for normal operation under the CP/M 
system, but can be overwritten by a transient program if the BDOS 
facilities are not required by the transient.
.pp
If, for example, a particular program performs only simple I/O 
and must begin execution at location 0, it can first be loaded 
into the TPA, using normal CP/M facilities, with a small memory 
move program that gets control when loaded.  The memory move 
program must get control from location 0100H, which is the 
assumed beginning of all transient programs.  The move program can
then proceed to the entire memory image down to location 0 and 
pass control to the starting address of the memory load.
.pp
If the BIOS is overwritten or if location 0, containing the warm 
start entry point, is overwritten, the operator must bring the 
CP/M system back into memory with a cold start sequence.
.sp 2
.tc    6.10  Disk Parameter Tables
.he CP/M Operating System Manual          6.10  Disk Parameter Tables
.sh
6.10  Disk Parameter Tables
.qs
.pp
Tables are included in the BIOS that describe the particular 
characteristics of the disk subsystem used with CP/M.  These 
tables can be either hand-coded, as shown in the sample CBIOS in 
Appendix B, or automatically generated using the DISKDEF macro 
library, as shown in Appendix F.  The purpose here is to describe 
the elements of these tables.
.bp
.pp
In general, each disk drive has an associated (16-byte) disk 
parameter header that contains information about the disk drive 
and provides a scratch pad area for certain BDOS operations.  The 
format of the disk parameter header for each drive is shown 
in Figure 6-2, where each element is a word (16-bit) value.
.mb 6
.fm 2
.sp 3
.nf
XLT     0000     0000     0000     DIRBUF     DPB     CSV     ALV
16b     16b      16b      16b      16b        16b     16b     16b
.fi
.sp 2
.sh
            Figure 6-2.  Disk Parameter Header Format
.sp 2
.pp
The meaning of each Disk Parameter Header (DPH) element is detailed in Table
6-7.
.sp 2
.sh
               Table 6-7.  Disk Parameter Headers
.sp
.nf
  Disk Parameter                 Meaning
      Header
.fi
.ll 60
.sp
.in 20
.ti -14
XLT           Address of the logical-to-physical translation vector, if used
for this particular drive, or the value 0000H if no sector translation
takes place (that is, the physical and logical sector numbers are the same).
Disk drives with identical sector skew factors share the same translate tables.
.sp
.ti -14
0000          Scratch pad values for use within the BDOS, initial value is
unimportant.
.sp
.ti -14
DIRBUF        Address of a 128-byte scratch pad area for directory operations
within BDOS.  All DPHs address the same scratch pad area.
.sp
.ti -14
DPB           Address of a disk parameter block for this drive.  Drives with
identical disk characteristics address the same disk parameter block.
.sp
.ti -14
CSV           Address of a scratch pad area used for software check for
changed disks.  This address is different for each DPH.
.sp
.ti -14
ALV           Address of a scratch pad area used by the BDOS to keep disk
storage allocation information.  This address is different for each DPH.
.fi
.in 0
.ll 65
.bp
.pp
Given n disk drives, the DPHs are arranged in a table whose first row of 16
bytes corresponds to drive 0, with the last row corresponding to drive n-1.
In the following figure the lable DPBASE defines the base address of the DPH
table.
.sp 3
.nf
   DPBASE:
.sp
      00  XLT 00  0000  0000  0000  DIRBUF DBP 00 CSV 00 ALV 00
.sp
      01  XLT 01  0000  0000  0000  DIRBUF DBP 01 CSV 01 ALV 01
                                    .
                                    .
                                    .
     n-1  XLTn-1  0000  0000  0000  DIRBUF DBTn-1 CSVn-1 ALVn-1
.fi
.sp 2
.sh
            Figure 6-3.  Disk Parameter Header Table
.sp 2
.pp
A responsibility of the SELDSK subroutine is to return the base address of
the DPH for the selected drive.  The following sequence of operations returns
the table address, with a 0000H returned if the selected drive does not exist.
.sp 2
.nf
.in 7
 NDISKS      EQU     4         ;NUMBER OF DISK DRIVES
 .....
 SELDSK:     ;SELECT DISK GIVEN BY BC
             LSI     H,0000H   ;ERROR CODE
             MOV     A,C       ;DRIVE OK?
             CPI     NDISKS    ;CY IF SO
             RNC               ;RET IF ERROR
             ;NO ERROR, CONTINUE
             MOV     L,C       ;LOW(DISK)
             MOV     H,B       ;HIGH(DISK)
             DAD     H         ;*2
             DAD     H         ;*4
             DAD     H         ;*8
             DAD     H         ;*16
             LXI     D,DPBASE;FIRST DPH
             DAD     D         ;DPH(DISK)
             RET
.fi
.in 0
.sp
.pp
The translation vectors, XLT 00 through XLTn-1, are located elsewhere in
the BIOS, and simply correspond one-for-one with the logical sector numbers
zero through the sector count 1.  The Disk Parameter Block (DPB) for each
drive is more complex.  As shown in Figure 6-4, particular DPB, that is
addressed by one or more DPHs, takes the general form:
.sp 3
.nf
    SPT   BSH   BLM   EXM   DSM   DRM   AL0   AL1   CKS   0FF
    16b   8b    8b    8b    16b   16b   8b    8b    16b   16b
.fi
.sp 2
.sh
            Figure 6-4.  Disk Parameter Block Format
.sp 3
where each is a byte or word value, as shown by the 8b or 16b indicator below
the field.
.pp
The following field abbreviations are used in Figure 6-4:
.sp 2
.in 5
.ti -2
o SPT is the total number of sectors per track.
.sp
.ti -2
o BSH is the data allocation block shift factor, determined by the data
block allocation size.
.sp
.ti -2
o BLM is the data allocation block mask (2[BSH-1]).
.sp
.ti -2
o EXM is the extent mask, determined by the data block allocation
size and the number of disk blocks.
.sp
.ti -2
o DSM determines the total storage capacity of the disk drive.
.sp
.ti -2
o DRM determines the total number of directory entries that can be
stored on this drive.  AL0, AL1 determine reserved directory blocks.
.sp
.ti -2
o CKS is the size of the directory check vector.
.sp
.ti -2
o 0FF is the number of reserved tracks at the beginning of the
(logical) disk.
.fi
.in 0
.sp
The values of BSH and BLM determine the data allocation size BLS,
which is not an entry in the DPB.  Given that the designer has selected a
value for BLS, the values of BSH and BLM are shown Table 6-8.
.sp 2
.sh
                 Table 6-8.  BSH and BLM Values
.nf
.sp
.in 18
  BLS         BSH         BLM
.sp
  1024         3            7
  2048         4           15
  4096         5           31
  8192         6           63
16,384         7          127
.fi
.in 0
.sp 2
where all values are in decimal.  The value of EXM depends upon both the BLS
and whether the DSM value is less than 256 or greater than 255, as shown in
Table 6-9.
.bp
.sh
                     Table 6-9.  EXM Values
.nf
.sp
                    BLS             EXM values
.sp
.in 18
            DSM<256    DSM>255
.sp
  1024         0         N/A
  2048         1          0
  4096         3          1
  8192         7          3
16,384        15          7
.fi
.in 0
.sp
.pp
The value of DSM is the maximum data block number supported by this
particular drive, measured in BLS units.  The product (DSM+1) is the
total number of bytes held by the drive and must be within the
capacity of the physical disk, not counting the reserved operating system
tracks.
.pp
The DRM entry is the one less than the total number of directory entries
that can take on a 16-bit value.  The values of AL0 and AL1, however, are
determined by DRM.  The values AL0 and AL1 can together be considered a
string of 16-bits, as shown in Figure 6-5.
.sp 3
.nf
                AL0                            AL1

 00  01  02  03  04  05  06  07  08  09  10  11  12  13  14  15
.fi
.sp 2
.sh
                    Figure 6-5.  AL0 and AL1
.sp 2
.pp
Position 00 corresponds to the high-order bit of the byte 
labeled AL0 and 15 corresponds to the low-order bit of the byte 
labeled AL1.  Each bit position reserves a data block for number 
of directory entries, thus allowing a total of 16 data blocks to 
be assigned for directory entries (bits are assigned starting at 
00 and filled to the right until position 15).  Each directory 
entry occupies 32 bytes, resulting in the following tabulation:
.sp 2
.sh
                  Table 6-10.   BLS Tabulation
.sp
.nf
.in 18
 BLS         Directory Entries
.sp
  1024         32 times # bits
  2048         64 times # bits
  4096        128 times # bits
  8192        256 times # bits
16,384        512 times # bits
.fi
.in 0
.bp
.pp
Thus, if DRM = 127 (128 directory entries) and BLS = 1024, there 
are 32 directory entries per block, requiring 4 reserved blocks.  
In this case, the 4 high-order bits of AL0 are set, resulting in 
the values AL0 = 0F0H and AL1 = 00H.
.pp
The CKS value is determined as follows:  if the disk drive media is 
removable, then CKS = (DRM+1)/4, where DRM is the last directory 
entry number.  If the media are fixed, then set CKS = 0 (no 
directory records are checked in this case).
.pp
Finally, the 0FF field determines the number of tracks that are 
skipped at the beginning of the physical disk.  This value is 
automatically added whenever SETTRK is called and can be used as 
a mechanism for skipping reserved operating system tracks or for 
partitioning a large disk into smaller segmented sections.
.pp
To complete the discussion of the DPB, several DPHs can address 
the same DPB if their drive characteristics are identical.  
Further, the DPB can be dynamically changed when a new drive is 
addressed by simply changing the pointer in the DPH; because the 
BDOS copies the DPB values to a local area whenever the SELDSK 
function is invoked.
.pp
Returning back to DPH for a particular drive, the two address
values CSV and ALV remain.  Both addresses reference an area of 
uninitialized memory following the BIOS.  The areas must be 
unique for each drive, and the size of each area is determined by 
the values in the DPB.
.pp
The size of the area addressed by CSV is CKS bytes, which is 
sufficient to hold the directory check information for this 
particular drive,  If CKS = (DRM+1)/4, you must reserve (DRM+1)/4 
bytes for directory check use.  If CKS = 0, no storage is 
reserved.
.pp
The size of the area addressed by ALV is determined by the 
maximum number of data blocks allowed for this particular disk 
and is computed as (DSM/8)+1.
.pp
The CBIOS shown in Appendix B demonstrates an instance of these 
tables for standard 8-inch, single-density drives.  It might be 
useful to examine this program and compare the tabular values 
with the definitions given above.
.sp 2
.tc    6.11  The DISKDEF Macro Library
.he CP/M Operating System Manual      6.11  The DISKDEF Macro Library
.sh
6.11  The DISKDEF Macro Library
.qs
.pp
A macro library called DISKDEF (shown in Appendix F), greatly 
simplifies the table construction process.  You must have access 
to the MAC macro assembler, of course, to use the DISKDEF 
facility, while the macro library is included with all CP.M 2 
distribution disks.
.bp
.pp
A BIOS disk definition consists of the following sequence of 
macro statements:
.sp
.nf
.in 7
 MACLIB         DISKDEF
 .....
 DISKS          n
 DISKDEF        0,...
 DISKDEF        1,...
 .....
 DISKDEF        n-1
 .....
 ENDEF
.fi
.in 0
.sp
where the MACLIB statement loads the DISKDEF.LIB file, on the 
same disk as the BIOS, into MAC's internal tables.  The DISKS 
macro call follows, which specifies the number of drives to be 
configured  with the user's system, where n is an integer in the 
range 1 to 16.  A series of DISKDEF macro calls then follow that 
define the characteristics of each logical disk, 0 through n-1, 
corresponding to logical drives A through P.  The DISKS and 
DISKDEF macros generate the in-line fixed data tables described 
in the previous section and thus must be placed in a 
nonexecutable portion of the BIOS, typically directly following 
the BIOS jump vector.
.pp
The remaining portion of the BIOS is defined following the 
DISKDEF macros, with the ENDEF macro call immediately preceding 
the END statement.  The ENDEF (End of Diskdef) macro generates 
the necessary uninitialized RAM areas that are located in 
memory above the BIOS.
.pp
The DISKDEF macro call takes the form:
.sp
.ti 8
DISKDEF  dn,fsc,lsc,[skf],bls dks,dir,cks,ofs,[0]
.sp
where
.sp
.in 5
.ti -2
o dn is the logical disk number, 0 to n-1.
.ti -2
o fsc is the first physical sector number (0 or 1).
.ti -2
o lsc is the last sector number.
.ti -2
o skf is the optional sector skew factor.
.ti -2
o bls is the data allocation block size.
.ti -2
o dks is the number of blocks on the disk.
.ti -2
o dir is the number of directory entries.
.ti -2
o cks is the number of checked directory entries.
.ti -2
o ofs is the track offset to logical track 00.
.ti -2
o [0] is an optional 1.4 compatibility flag.
.fi
.in 0
.sp
.pp
The value dn is the drive number being defined with this DISKDEF 
macro invocation.  The fsc parameter accounts for differing 
sector numbering systems and is usually 0 to 1.  The lsc is the 
last numbered sector on a track.  When present, the skf parameter 
defines the sector skew factor, which is used to create a sector 
translation table according to the skew.
.pp
If the number of sectors is less than 256, a single-byte table is 
created, otherwise each translation table element occupies two 
bytes.  No translation table is created if the skf parameter is 
omitted, or equal to 0.
.pp
The bls parameter specifies the number of bytes allocated to each 
data block, and takes on the values 1024, 2048, 4096, 8192, or 
16384.  Generally, performance increases with larger data block 
sizes because there are fewer directory references, and logically 
connected data records are physically close on the disk.  
Further, each directory entry addresses more data and the BIOS-resident
RAM space is reduced.
.pp
The dks parameter specifies the total disk size in bls units.  
That is, if the bls = 2048 and dks = 1000, the total disk 
capacity is 2,048,000 bytes.  If dks is greater than 255, the 
block size parameter bls must be greater than 1024.  The value of 
dir is the total number of directory entries that might exceed 
255, if desired.
.pp
The cks parameter determines the number of directory items to 
check on each directory scan and is used internally to detect 
changed disks during system operation, where an intervening cold 
or warm start has not occurred.  When this situation is detected, 
CP/M automatically marks the disk Read-Only so that data is not 
subsequently destroyed.
.pp
As stated in the previous section, the value of cks = dir when 
the medium is easily changed, as is the case with a floppy disk 
subsystem.  If the disk is permanently mounted, the value of cks 
is typically 0, because the probability of changing disks without a 
restart is low.
.pp
The ofs value determines the number of tracks to skip when this 
particular drive is addressed, which can be used to reserve 
additional operating system space or to simulate several logical 
drives on a single large capacity physical drive.
Finally, the [0] parameter is included when file compatibility is 
required with versions of 1.4 that have been modified for higher 
density disks.  This parameter ensures that only 16K is allocated 
for each directory record, as was the case for previous versions.  
Normally, this parameter is not included.
.pp
For convenience and economy of table space, the special form:
.sp
.ti 8
DISKDEF      i,j
.sp
gives disk i the same characteristics as a previously defined 
drive j.  A standard four-drive, single-density system, which is 
compatible with version 1.4, is defined using the following macro 
invocations:
.sp
.nf
.in 7
 DISKS        4
 DISKDEF      0,1,26,6,1024,243,64,2
 DISKDEF      1,0
 DISKDEF      2,0
 DISKDEF      3,0
 ....
 ENDEF
.fi
.in 0
.sp
with all disks having the same parameter values of 26 sectors per 
track, numbered 1 through 26, with 6 sectors skipped between each 
access, 1024 bytes per data block, 243 data blocks for a total of 
243K-byte disk capacity, 64 checked directory entries, and two 
operating system tracks.
.pp
The DISKS macro generates n DPHs, starting at the DPH table 
address DPBASE generated by the macro.  Each disk header block 
contains sixteen bytes, as described above, and correspond
one-for-one to each of the defined drives.  In the four-drive 
standard system, for example, the DISKS macro generates a table 
of the form:
.sp
.nf
.in 5
DPBASE     EQU$
DPE0:      DW XLT0,0000H,0000H,0000H,DIRBUF,DPB0,CSV0,ALV0
DPE1:      DW XLT0,0000H,0000H,0000H,DIRBUF,DPB0,CSV1,ALV1
DPE2:      DW XLT0,0000H,0000H,0000H,DIRBUF,DPB0,CSV2,ALV2
DPE3:      DW XLT0,0000H,0000H,0000H,DIRBUF,DPB0,CSV3,ALV3
.fi
.in 0
.sp
where the DPH labels are included for reference purposes to show 
the beginning table addresses for each drive 0 through 3.  The 
values contained within the DPH are described in detail in the 
previous section.  The check and allocation vector addresses are 
generated by the ENDEF macro in the ram area following the BIOS 
code and tables.
.pp
Note that if the skf (skew factor) parameter is 
omitted, or equal to 0, the translation table is omitted and a 
0000H value is inserted in the XLT position of the DPH for the 
disk.  In a subsequent call to perform the logical-to-physical 
translation, SECTRAN receives a translation table address of DE = 
0000H and simply returns the original logical sector from BC in 
the HL register pair.
.pp
A translate table is constructed when the skf parameter is 
present, and the (nonzero) table address is placed into the 
corresponding DPHs.  The following for example, is constructed 
when the standard skew factor skf = 6 is specified in the DISKDEF 
macro call:
.sp
.nf
.in 8
XLT0:    DB    1,7,13,19,25,5,11,17,23,3,9,15,21
         DB    2,8,14,20,26,6,12,18,24,4,10,16,22
.fi
.in 0
.pp
Following the ENDEF macro call, a number of uninitialized data
areas are defined.  These data areas need not be a part of the BIOS
that is loaded upon cold start, but must be available between the 
BIOS and the end of memory.  The size of the uninitialized RAM
area is determined by EQU statements generated by the ENDEF macro.
For a standard four-drive system, the ENDEF macro might produce
the following EQU statement:
.bp
.nf
.in 8
4C72 =        BEGDAT EQU $
              (data areas)
.sp
4DB0 =        ENDDAT EQU $
.sp
013C =        DATSIZ EQU $-BEGDAT
.fi
.in 0
.sp
which indicates that uninitialized RAM begins at location 4C72H, 
ends at 4DB0H-1, and occupies 013CH bytes.  You must ensure 
that these addresses are free for use after the system is loaded.
.pp
After modification, you can use the STAT program to 
check drive characteristics, because STAT uses the disk parameter 
block to decode the drive information.  A STAT command of the form:
.sp
.ti 8
STAT d:DSK:
.sp
decodes the disk parameter block for drive d (d=A,...,P) and 
displays the following values:
.sp 2
.nf
.in 8
r:  128-byte record capacity
k:  kilobyte drive capacity
d:  32-byte directory entries
c:  checked directory entries
e:  records/extent
b:  records/block
s:  sectors/track
t:  reserved tracks
.fi
.in 0
.sp
.pp
Three examples of DISKDEF macro invocations are shown below with 
corresponding STAT parameter values.  The last example produces a full
8-megabyte system.
.sp
.nf
.in 8
           DISKDEF 0,1,58,,2048,256,128,128,2
r=4096,    k=512, d=128, c=128, e=256, b=16, s=58, t=2
.sp
           DISKDEF 0,1,58,,2048,1024,300,0,2
r=16348,   k=2048, d=300, c=0, e=128, b=16, s=58, t=2
.sp
           DISKDEF 0,1,58,,16348,512,128,128,2
r=65536,   k=8192, d=128, c=128, e=1024, b=128, s=58, t=2
.fi
.in 0
.sp 2
.tc    6.12  Sector Blocking and Deblocking
.he CP/M Operating System Manual        6.12  Blocking and Deblocking
.sh
6.12  Sector Blocking and Deblocking
.qs
.pp
Upon each call to BIOS WRITE entry point, the CP/M BDOS includes 
information that allows effective sector blocking and deblocking 
where the host disk subsystem has a sector size that is a 
multiple of the basic 128-byte unit.  The purpose here is to 
present a general-purpose algorithm that can be included within 
the BIOS and that uses the BDOS information to perform the 
operations automatically.
.pp
On each call to WRITE, the BDOS provides the following 
information in register C:
.sp
.nf
.in 8
0   =   (normal sector write)
1   =   (write to directory sector)
2   =   (write to the first sector
        of a new data block)
.fi
.in 0
.pp
Condition 0 occurs whenever the next write operation is into a 
previously written area, such as a random mode record update; 
when the write is to other than the first sector of an 
unallocated block; or when the write is not into the directory 
area.  Condition 1 occurs when a write into the directory area is 
performed.  Condition 2 occurs when the first record (only) of a 
newly allocated data block is written.  In most cases, 
application programs read or write multiple 128-byte sectors in 
sequence; thus, there is little overhead involved in either 
operation when blocking and deblocking records, because preread 
operations can be avoided when writing records.
.pp
Appendix G lists the blocking and deblocking algorithms in 
skeletal form; this file is included on your CP/M disk.  
Generally, the algorithms map all CP/M sector read operations 
onto the host disk through an intermediate buffer that is the 
size of the host disk sector.  Throughout the program, values and 
variables that relate to the CP/M sector involved in a seek 
operation are prefixed by sek, while those related to the host 
disk system are prefixed by hst.  The equate statements beginning 
on line 29 of Appendix G define the mapping between CP/M and the 
host system, and must be changed if other than the sample host 
system is involved.
.pp
The entry points BOOT and WBOOT must contain the initialization 
code starting on line 57, while the SELDSK entry point must be 
augmented by the code starting on line 65.  Note that although 
the SELDSK entry point computes and returns the Disk Parameter 
Header address, it does not physically select the host disk at 
this point (it is selected later at READHST or WRITEHST).  
Further, SETTRK, SETTRK, and SETMA simply store the values, but 
do not take any other action at this point.  SECTRAN performs a 
trivial function of returning the physical sector number.
.pp
The principal entry points are READ and WRITE, starting on lines 
110 and 125, respectively.  These subroutines take the place of 
your previous READ and WRITE operations.
.pp
The actual physical read or write takes place at either WRITEHST 
or READHST, where all values have been prepared:  hstdsk is the 
host disk number, hsttrk is the host track number, and
hstsec is the host sector number, which 
may require translation to physical sector number.  You must 
insert code at this point that performs the full sector read or write
into or out of the buffer at hstbuf of length hstsiz.  All other mapping 
functions are performed by the algorithms.
.pp
This particular algorithm was tested using an 80-megabyte hard 
disk unit that was originally configured for 128-byte sectors, 
producing approximately 35 megabytes of formatted storage.  When 
configured for 512-byte host sectors, usable storage increased to 
57 megabytes, with a corresponding 400% improvement in overall 
response.  In this situation, there is no apparent overhead 
involved in deblocking sectors, with the advantage that user 
programs still maintain 128-byte sectors.  This is primarily 
because of the information provided by the BDOS, which eliminates 
the necessity for preread operations.
.sp 2
.ce
End of Section 6













