mirror of
https://github.com/wwarthen/RomWBW.git
synced 2026-02-06 22:33:12 -06:00
230 lines
11 KiB
Plaintext
230 lines
11 KiB
Plaintext
NOTES on your CP/M 3.0 BIOS and ZPM3
|
||
====================================
|
||
Last updated 19/4/92
|
||
|
||
ZPM3 will work fine with your current CP/M 3.0 BIOS. This
|
||
document is not meant to tell you how to change your BIOS for
|
||
ZPM3, but rather to point out some interesting and useful facts
|
||
about the way ZPM3 uses the BIOS, and how you should configure
|
||
your BIOS.
|
||
|
||
|
||
|
||
XMOVE routine.
|
||
~~~~~~~~~~~~~~
|
||
If you have 128 byte physical sectors, or your BIOS does all the
|
||
deblocking so that it appears to the BDOS that you have 128 byte
|
||
physical sectors, XMOVE does not get used at all by ZPM3. Such
|
||
was not the case with CP/M 3.0 which would make redundant calls
|
||
to XMOVE. Make sure XMOVE is implemented and working anyhow as
|
||
applications may attempt to use it.
|
||
|
||
When the BDOS is operating in the system bank (bank 0) and it
|
||
needs to move data in the TPA bank, it switches to the TPA bank
|
||
and does an ordinary LDIR. As such, XMOVE will never get called
|
||
by the BDOS with B=C (source bank and destination bank the same).
|
||
|
||
In the CP/M 3.0 manuals, there are two differing opinions about
|
||
XMOVE as far as whether B is the source or the destination. The
|
||
truth is that C is the source and B is the destination. Anything
|
||
you see to the contrary is a misprint.
|
||
|
||
MOVE routine.
|
||
~~~~~~~~~~~~~
|
||
When CP/M 3.0 was released, it was made 8080 compatible simply
|
||
because CP/M 2.2 was 8080 compatible. I have never heard of an
|
||
8080 machine running CP/M 3.0, and it is likely that there has
|
||
never been one. Digital Research knew that the Z80 was the CPU of
|
||
choice for modern PC's, and while they wrote their code for the
|
||
8080, they recognised the Z80 with the MOVE routine (which a Z80
|
||
BIOS could implement in just three instructions).
|
||
|
||
ZPM3 uses the MOVE routine much less than CP/M 3.0 does. In fact,
|
||
the only time ZPM3 uses MOVE is with an XMOVE call directly
|
||
preceding it. If you have 128 byte physical sectors (or the BIOS
|
||
does the sector deblocking), MOVE will never get called.
|
||
|
||
Always remember that MOVE must return with HL and DE pointing to
|
||
the end of the moved data. If they don't, you will have trouble.
|
||
|
||
|
||
TIME routine.
|
||
~~~~~~~~~~~~~
|
||
Be aware that the DATE program supplied with CP/M 3.0 will not
|
||
work properly if your BIOS does not update the SCB with
|
||
interrupts. There have been replacements since then that are
|
||
available in the public domain.
|
||
|
||
One common trap for BIOS writers is forgetting that HL and DE
|
||
must be saved by the TIME routine. There is no obvious reason for
|
||
it, and really they should be saved in the BDOS.
|
||
|
||
ZPM3 does not expect HL to be saved. If you have had trouble with
|
||
your CP/M 3.0 clock things might work now. It was decided that
|
||
seeing as TIME was the only routine (apart from MOVE) which
|
||
required HL to be saved, it was too easy to overlook, and a real
|
||
pain to implement (some systems use HL to switch banks on entry
|
||
to the BIOS. MOVE is always accounted for, but TIME sometimes
|
||
isn't (Morrow MD11 owners take note!)).
|
||
|
||
Ideally, there should be no reason to save HL in your BIOS,
|
||
unless you intend to run CP/M 3.0 sometimes (although I can't
|
||
imagine why). Any applications which attempt to use TIME through
|
||
the function 50 are not guaranteed that HL will be saved anyhow.
|
||
|
||
Buffers.
|
||
~~~~~~~~
|
||
CP/M 3.0 (and therefore ZPM3) keeps special disk buffers. The
|
||
system is rather complex. The directory is buffered separately
|
||
from the rest of the disk (and in the case of 128 byte sectors
|
||
the rest of the disk isn't buffered anyhow).
|
||
|
||
You decide how many buffers to give to each disk's directory and
|
||
data, and you may choose to have buffers shared by different
|
||
drives. All these choices can make for lots of fun for the
|
||
hacker, but without knowing much about the internal workings of
|
||
the BDOS how do you best set the buffer up?
|
||
|
||
There are many cases to consider depending on how much RAM you
|
||
have available to allocate to buffers. If you have virtually
|
||
unlimited RAM, you might as well allocate as many buffers as
|
||
GENCPM will allow. The only catch to this is that more buffers
|
||
implies the BDOS will take more time to look through them all
|
||
before coming to the decision that a disk read is required. The
|
||
good news is that the ZPM3 searching algorithm is particularly
|
||
fast. Empty buffers are discovered even faster than buffers
|
||
which are valid but don't match, so large numbers of empty
|
||
buffers pose very little problem. In general, even with the
|
||
maximum number of buffers, the advantages they give outweigh the
|
||
disadvantages.
|
||
|
||
Of course, few people have unlimited RAM. If you have very little
|
||
room available, spend most of it on the directory buffers. These
|
||
buffers act like a cache of the directory, and can save the disk
|
||
heads from moving back to the directory tracks to find out where
|
||
the next block is stored. Even on very fast hard disks, the
|
||
advantages that decent directory buffers give are great.
|
||
|
||
When dividing up directory buffers between a number of drives,
|
||
consider which drive holds the most files and which drive does
|
||
the most work. A drive which holds a lot of files but is rarely
|
||
accessed is not worth wasting buffers on. If you have a system
|
||
with one hard drive and one floppy drive, and you don't intend to
|
||
use the floppy drive very much, give only one buffer to the
|
||
floppy and all the rest to your hard drive. This will penalise
|
||
the floppy's performance somewhat, but the improvement it gives
|
||
to the hard drive will make it worthwhile.
|
||
|
||
Data buffers, like directory buffers, perform two tasks:
|
||
deblocking of physical sectors, and cacheing. For data buffers
|
||
however the cacheing is the less important job, unless you have a
|
||
lot of data buffers available. The reason for this is that the
|
||
buffer algorithms work by taking the least recently used buffer
|
||
and using it for deblocking. If you are working on a file which
|
||
is 8k long, but you only have 4k of buffers, the BDOS will run
|
||
out of buffers before it has read the whole file and will grab
|
||
the least recently used one even though it contains valid data
|
||
from the file which could be required later on. The result is
|
||
that the BDOS does much searching through its 4k of buffers, but
|
||
rarely finds anything which matches and must read from the disk
|
||
anyhow.
|
||
|
||
In practice the system works a little better than that because of
|
||
the way files are used by most programs, so data buffers are
|
||
still worthwhile, but to take real advantage of their cacheing
|
||
ability you must have more room in the data buffers than the size
|
||
of the file you are working with. With word processors such as
|
||
Wordstar and NewWord creating extra files as they work, you
|
||
really need more than twice as much room in the buffers than the
|
||
size of the file.
|
||
|
||
So you can see why data buffers are less important than directory
|
||
buffers. Something else you should be aware of concerns multi-
|
||
sector i/o and the data buffers. When the BDOS is told to read a
|
||
file it searches its buffers and if it can't find the data there
|
||
it reads it from the disk. Normally it deblocks the data one
|
||
record at a time through its data buffers, leaving the data in
|
||
the buffers in case it is required again. However multi-sector
|
||
i/o does not usually need to deblock its data, so the data is
|
||
sent straight to the TPA without going through the data buffers.
|
||
If any of that data is required again, it will not be in the data
|
||
buffers and must be read from the disk. So two reads of the same
|
||
data using multi-sector i/o might actually be slower than reads
|
||
that are done a sector at a time!
|
||
|
||
And the really important thing about all this is that the CCP
|
||
uses multi-sector i/o to load programs. So if you thought that
|
||
implementing large numbers of data buffers would give you faster
|
||
loading of programs, you were wrong. The data buffers won't help
|
||
program loading unless the data can be put into the buffers
|
||
first.
|
||
|
||
If you use ZCCP, you will find there is a facility to prevent the
|
||
data buffers from being bypassed on program loads. It involves
|
||
simply setting the f1' bit of the file. The idea is that you set
|
||
f1' on all the files which are small enough not to clog up your
|
||
buffers, and then they run as if they are on a ram disk, but one
|
||
in which you can never lose data. The system is quite wonderful
|
||
in that the RAM used to hold the files is available to buffer
|
||
other data if required. Unlike a ram disk, the RAM is dynamically
|
||
allocated and the data is completely safe. But you must be using
|
||
ZCCP, and you must have at least 6k of data buffers before it
|
||
does anything useful. If you currently have a ram disk but few
|
||
data buffers, consider taking a chunk of your ram disk for data
|
||
buffers and switching to ZCCP.
|
||
|
||
CPMLDR bug.
|
||
~~~~~~~~~~~
|
||
This is closely related to the subject of buffers because you
|
||
will find that if you increase your buffers past a certain point,
|
||
the system will not boot. Almost certainly you will suspect a
|
||
problem with your BIOS code (you normally should), however the
|
||
CPMLDR.REL code supplied by DRI has a bug in it.
|
||
|
||
You may be wondering if everything DRI did with CP/M 3.0 was
|
||
buggy! I must say that what they achieved was terrific, but it
|
||
had its faults as well. Hopefully ZPM3 has addressed them all.
|
||
|
||
The CPMLDR problem occurs when your CPM3.SYS grows from being 16k
|
||
or less, to over 16k (and therefore two logical extents). You may
|
||
not have this problem under certain drive configurations, but if
|
||
you do, the symptom is that described above.
|
||
|
||
There really is no way of patching around this, but if you have
|
||
your loader BIOS, you can certainly use the (somewhat superior)
|
||
ZPM3LDR.REL code instead. This works very similarly to the DRI
|
||
code, except that it works properly. Unlike the DRI code, you
|
||
will find that ZPM3LDR has all its messages at the head of the
|
||
file so that you can patch them and change them if you wish.
|
||
|
||
ZPM3LDR does not clear the screen on boot up (CPMLDR does by
|
||
sending multiple linefeeds), but you could patch this if you
|
||
like. ZPM3LDR.REL will directly replace CPMLDR.REL. ZPM3LDR
|
||
however does not use the MOVE routine that CPMLDR requires
|
||
(although there is nothing much to be gained by removing it from
|
||
your loader bios code).
|
||
|
||
|
||
GENCPM bugs.
|
||
~~~~~~~~~~~~
|
||
GENCPM has bugs in it. If you can, try and set up all your
|
||
buffers manually. That way you'll know where they are and you are
|
||
in complete control.
|
||
|
||
The biggest fault I have found with GENCPM is that it will
|
||
allocate allocation vectors incorrectly. CP/M 3.0 can use double
|
||
bit allocation vectors, but doesn't necessarily. Sometimes (and I
|
||
think it is mainly with big disks), GENCPM will only allocate
|
||
enough room for single bit allocation vectors when double bit
|
||
vectors had been specified. The symptoms of this are varied, but
|
||
often, you can use your A: drive for a while, but as soon as you
|
||
use your B: drive funny things happen. If you only use A: and C:
|
||
drives, things appear to work OK.
|
||
|
||
The first thing to try if you suspect a GENCPM induced problem is
|
||
setting up with only one drive and a single buffer. If that fixes
|
||
it, the problem could well be with GENCPM.
|
||
|
||
Naturally, your BIOS code could still be the problem, so look out
|
||
for that too!
|
||
|