[comp.sys.apple] Apple 1 Meg Memory driver bug

brianw@microsoft.UUCP (Brian Willoughby) (10/14/89)

I found another bug in the ROM code for the Apple 1 Meg Memory driver.
My last few 'bug reports' have turned out to be old news (remember
Basic.System?), but I guess I should mention this in case it isn't
common knowledge.

I don't have my printouts here at work, but if this turns out to be a
real bug then I can cite the addresses of the bug.

The Memory card driver converts both ProDOS and SmartPort calls (actually
all the different OS calls) to the same format and then handles the
transfer to/from the RAMDisk from a core routine.  During the transfer,
any return codes generated are stored in screenholes for later use (i.e.
$07F8+Slot).  There is an address for the Accumulator (error code) and
both the X and Y registers.  I'll explain what their return values mean
later.

Now I'm starting to get vague, because I can't remember if the 'read' or
'write' core routine has the bug, but you should be able to find the bug
if you know a little about the Memory driver $C8xx space routines.  The
read/write core routines are generic in that they move integral numbers
of block(s) OR a specified number of bytes (not necessarily complete
blocks).  The ProDOS calls only access one block at a time, but the
SmartPort Read and Write calls can ask for any number of bytes to be
transferred.  Like any good interface, the actual number of bytes that
were successfully transferred is returned to the caller.  In this case
the X and Y registers hold the high byte and low byte of the total number
of bytes transferred.

The bug comes from the fact that one of the index registers is not
updated, because the code which stores to that register's screenhole is
branched around.  The read/write core routines are each entered with a
few direct page registers holding the number of bytes to transfer.  Since
ProDOS only ask for blocks, the 'low byte' of the 'number of bytes to
transfer' will always be zero.  The core routines have a branch statement
which checks for zero, and branches around the code which moves the final
partial block.  The problem is that in one of the routines (read or
write, can't remember), the instructions which update the 'actual number
of byte transfered' return value is not set to zero because that
instruction is branched around.  In the complementary routine (write or
read), the store occurs BEFORE the branch and is always executed.

So here is what this all translates to.  If a call is made from an OS
routine which expects X and Y as return values, then there is one case
where these will not be correctly updated.  The low byte of the 'actual
number of bytes transferred' is only correctly updated if you ask for a
non-integral number of pages/blocks.  If it is supposed to be zero, then
the value is not written, so the return code is whatever value happens to
be in the appropriate screenhole.

I think that this bug would be very easy to miss for several reasons:
- Most of the OS calls do not define return values for X and Y.  These
are also the most common way to access a RAMDrive (i.e. ProDOS or
SmartPort Block calls).
- The return value in the screenhole might already be set to zero from a
previous call to the memory card, so the correct result might be
magically appearing.  Transfers of whole pages are much more common than
odd numbers of bytes.
- Not many applications use the SmartPort Read and Write calls to do
transfers (I think that this call is the only one that uses the return
code anyway).

Sorry if this is not clear, I wrote without any references around, but I
wanted to post this before the weekend.  I'm sure its a known bug anyway.
I'm sorry that I can't remember whether it read or write routine has the
bug, but since you need to look at both anyway, that should be easy.  I
also can't remember whether the X or Y register isn't updated - its
whichever one that holds the low byte of the 'number of bytes
transferred'.  I sure hope thats enough info to find the bug.

Brian Willoughby
UUCP:           ...!{tikal, sun, uunet, elwood}!microsoft!brianw
InterNet:       microsoft!brianw@uunet.UU.NET
  or:           microsoft!brianw@Sun.COM
Bitnet          brianw@microsoft.UUCP