# Converting Apple II ProDOS blocks to DOS tracks and sectors

The 8-bit Apple II had two disk operating systems with different disk access semantics.

DOS used tracks and sectors. A sector is 256 bytes.

ProDOS used blocks. A block is 512 bytes.

But mapping from ProDOS blocks to tracks and sectors seems to use some kind of interleaving. And, confusingly, I find two different mappings when trying to Google how this worked:

# Just Solve the File Format Problem

Figure B-15 shows how to determine a block number from a given track and sector. First multiply the track number by 8, then add the Sector Offset that corresponds to the sector number. The half of the block in which the sector resides is determined by the Half-of-Block line (1 is the first half; 2 is the second).

Figure B-15. Tracks and Sectors to Blocks

``````      Block = (8 * Track) + Sector Offset
Sector : 0 1 2 3 4 5 6 7 8 9 A B C D E F
Sector Offset : 0 7 6 6 5 5 4 4 3 3 2 2 1 1 0 7
Half of Block: 1 1 2 1 2 1 2 1 2 1 2 1 2 1 2 2
``````
• Block 0 -> Track 0 Sector 0 + Track 0 Sector 14
• Block 1 -> Track 0 Sector 12 + Track 0 Sector 13
• Track 0 Sector 0 -> Block 0 (first half)
• Track 0 Sector 1 -> Block 7 (first half)

# Apple ][ ProDOS Operating System Technical Information

``````1390 *      READ/WRITE A BLOCK
1400 *
1410 *      1. ASSURE VALID BLOCK NUMBER (0...279)
1420 *      2. CONVERT BLOCK NUMBER TO TRACK/SECTOR
1430 *         TRACK = INT(BLOCK/8)
1440 *         BLOCK   SECTORS
1450 *         ----- ---------
1460 *           0     0 AND 2
1470 *           1     4 AND 6
1480 *           2     8 AND 10
1490 *           3    12 AND 14
1500 *           4     1 AND 3
1510 *           5     5 AND 7
1520 *           6     9 AND 11
1530 *           7    13 AND 15
1540 *      3. CALL RWTS TWICE
``````
• Block 0 -> Track 0 Sector 0 + Track 0 Sector 2
• Block 1 -> Track 0 Sector 4 + Track 0 Sector 6
• Track 0 Sector 0 -> Block 0 (first half)
• Track 0 Sector 1 -> Block 4 (first half)

What am I missing?? Is there some other level of indirection? Does one or both actually use logical blocks and sectors as well as physical blocks and sectors?

I'm actually trying to work with .dsk disk image files if that makes a difference. They are raw disk images with no headers but come in two flavours, a raw dump of DOS tracks and sectors in order or a raw dump of ProDOS blocks in order. Perhaps there is something about how these image formats relate to the actual disks or to each DOS that I am missing??

## 1 Answer

DOS-ordered images were created by DOS programs that started reading from track 0 sector 0, continued to sector 15, moved to track 1 sector 0, and so on until the end of the disk. They are in DOS logical order: the first 256 bytes are T0S0, the next are T0S1, and so on.

ProDOS-ordered images are created by ProDOS programs that started reading from block 0, then read block 1, and so on until the end of the disk. They are in ProDOS block order: the first 512 bytes are block 0, the next are block 1, and so on.

You can find the CiderPress conversion tables in the `CalcSectorAndOffset` function here. For sanity it converts logical to physical then physical to logical when translating between formats. For example:

``````static const int raw2dos[16] = {
0, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 15
};
static const int dos2raw[16] = {
0, 13, 11, 9, 7, 5, 3, 1, 14, 12, 10, 8, 6, 4, 2, 15
};
static const int raw2prodos[16] = {
0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15
};
static const int prodos2raw[16] = {
0, 2, 4, 6, 8, 10, 12, 14, 1, 3, 5, 7, 9, 11, 13, 15
};
``````

You can see that `prodos2raw` lists sector 0, 2, 4, 6, and so on, which matches the order in your ProDOS table for blocks 0 and 1.

So if you have a ProDOS filesystem on a ProDOS-ordered image, and you want to read block 1, you grab `prodos2raw[2]` and `[3]`, which are 4 and 6. You look up `raw2prodos[4]` and `[6]`, which are 2 and 3. So you read from offset 2*256 and 3*256 to form your 512-byte block.

If you have a ProDOS filesystem on a DOS-ordered image, and you want to read block 1, you do the same thing but with `raw2dos`, which returns 13 and 12. So you read from offset 13*256 and 12*256 to form your 512-byte block.

This is all within a single 4096-byte track on a 140KB disk image. Add 4096 per track (or block num / 8) to the file offset.