The code translates the Logical Block Address (LBA) passed in register AX
and converts it to Cylinder/Head/Sector (CHS). I explain the general calculation in an answer to a related Stackoverflow question in the section Translation of LBA to CHS
.
Translation of LBA to CHS
Definitions:
LBA is the logical block address
HPC is the maximum number of heads per cylinder (reported by
disk drive, typically 16 for 28-bit LBA)
SPT is the maximum number of sectors per track (reported by
disk drive, typically 63 for 28-bit LBA)
MOD is the modulo operation, i.e. the remainder
÷ is integer division, i.e. the quotient of the division
where any fractional part is discarded
What you need is a proper LBA to CHS conversion routine. Since you
will need such a function for different aspect of navigating FAT12
file structures it is best to create a function. We'll call it
lba_to_chs
.
Before we write such code we should revisit the equation earlier:
C = LBA ÷ (HPC × SPT)
H = (LBA ÷ SPT) mod HPC
S = (LBA mod SPT) + 1
We could implement this as is, but if we rework the equation for
cylinders we can reduce the amount of work we have to do. C = LBA ÷ (HPC × SPT)
can be rewritten as:
C = LBA ÷ (HPC × SPT)
C = LBA ÷ (SPT × HPC)
C = (LBA ÷ SPT) × (1 ÷ HPC)
C = (LBA ÷ SPT) ÷ HPC
If we now look at the revised formula we have:
C = (LBA ÷ SPT) ÷ HPC
H = (LBA ÷ SPT) mod HPC
S = (LBA mod SPT) + 1
Now we should notice that (LBA ÷ SPT)
is duplicated in two places.
We only have to do that equation once. As well since x86 DIV
instruction computes the remainder and quotient at the same time we
also end up computing LBA mod SPT
for free when we do (LBA ÷ SPT)
.
The code would follow this structure:
- Compute LBA DIV SPT . This yields:
(LBA ÷ SPT)
in the quotient
(LBA mod SPT)
in the remainder
- Take the remainder from step (1) and put in temporary register
- Add 1 to the temporary in step (2). That register now contains the sector as computed by
S = (LBA mod SPT) + 1
- Take quotient from step (1) and divide by HPC.
- Cylinder number will be the quotient
- Head will be the remainder.
We have reduced the equation down to a couple DIV instructions and
an increment/add. We can simplify things more. If we assume we are
using well known IBM Compatible Disk formats then we can also say that
Sectors per Track (SPT), Heads(HPC), Cylinder, Head, and Sector will
always be less than 256. When the maximum LBA on any well known floppy
disk format is divided by SPT the result will always be less than 256.
Knowing this allows us to avoid bit twiddling the top two bits of the
cylinder and placing them in the top two bits of CL. We can also use
DIV instructions that do 16-bit by 8-bit unsigned division.
Your assembly code is very similar in nature.
Function inputs:
- The parameter LBA for the function is in
AX
- Word at address 0x7C18 is the Sectors Per Track stored in the disk's BIOS Parameter Block (BPB).
- Word at address 0x7C1A is the Number Of Heads as stored in the BPB.
Function outputs (after the calculations):
- Byte at address 0x7C3B is where the computed Sector # is stored.
- Byte at address 0x7C2A is where the computed Head # is stored.
- Word at address 0x7C39 is where the computed Cylinder # is stored.