How to read CP/M directory?

Started by MIRKOSOFT, June 20, 2010, 10:20 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

MIRKOSOFT

Hi!

I want to read and show CP/M disk directory.

Always when I use standard directory reading it shows only one USR file 'cause it reads GCR format...

Can anybody help me how to show CP/M directory without switching to CP/M mode?

Many many thanks.

Miro
MIRKOSOFT of megabytes

Commodore 64 was great, Commodore 128 is bigger, better, faster and more!!!

http://www.mirkosoft.sk

LokalHorst

#1
Hi Miro,
are you sure you want to do it? - because it's a very tedious task without the cp/m bios/bdos in the background.
CP/M directories (and related file organisation) has nothing in common with the native commodore filesystem.
A small correction at the beginning - the 1581, you're referring to with your question regarding the autostart 'usr' file, doesn't  use gcr coding at all - there's only a mfm controller (wd1770) inside - it uses either it's native mfm format or a so called 'logical' format which is somewhat compatible to the former diskdrives with 256byte sectors.
1581 physical layout: tracks 0 to 79, 10 x 512byte sectors 1 to 10, 2 sides
1581 logical (emulated): tracks 1 to 80, 40 x 256byte sectors 0 to 39 (# 20 to 39 on the 2nd side).
Things you'll need to achieve your (whatever) task:
Full sector read routine - preferably burst mode
A 4Kbyte buffer to hold the retrieved directory data
A optional 1K work buffer.
There are 4 official commodore CP/M formats:
c64 single sided:
using 32 tracks, 17 x 256byte sectors,
136K total, 1K allocation units
2K dir space = 64 entries,
dir start @ track 3 sector 0
the directory uses sectors 0,1,2,3,4,5,6,7
first data block starts @ track 3 sector 8 (allocation unit 2)
track 18 is skipped in CP/M and track 1 & 2 are reserved as system tracks.

c128 single sided:
using 680 of the 683 totally available sectors with a special translation scheme grouping 4 x 256bytes sectors to a pseudo 1024byte sector (skew 5),
170K total, 1K allocation units,
2K dir space = 64 entries,
dir starts @ track 1 sector 10,
the dir uses:
T1/S10;T1/S15;T1/S20;T1/S4 (alloc unit 0)
T1/S9;T1/S14;T1/S19;T1/S3 (alloc unit 1)
Sector 0 & 5 of track 1 and track 18 sector 0 are skipped in CP/M.
first datablock starts @ T1/S8;T1/S13;T1/S18;T1/S2 (alloc unit 2)

c128 double sided:
using 1360 sectors grouped the same as the single sided version,
skipping additionally T36/S0;T36/S5;T53/S0
340K total, 2K allocation units
4K dir space = 128 entries,
dir starts @ track 1 sector 10,
the dir uses:
T1/S10;T1/S15;T1/S20;T1/S4 (alloc unit 0)
T1/S9;T1/S14;T1/S19;T1/S3
T1/S8;T1/S13;T1/S18;T1/S2 (alloc unit 1)
T1/S7;T1/S12;T1/17;T1/S1
first datablock starts @
T1/S6;T1/S11;T1/S16;T2/S0 (alloc unit 2)
T2/T5;T2/S10;T2/S15;T2/S20
CP/M distinguishes the single from the double sided format by reading the last byte from the boot sector T1/S0 -> if $00 then SS, if $FF then DS

1581 CP/M format:
the disk is accessed in it's physical format grouping two 512byte sectors to a pseudo 1024byte sector. The native format dir track is skipped T39/S1 to S10 (logical T40/S0 to S19) it holds a autostart prog. and a modified cpmldr to boot from this drive.
Using 794K total, 2K allocation units (0 to 396 -> 16bit pointers)
4K dir space = 128 entries,
dir starts @ track 1 sector 0 (using logical 256byte addr.)
the dir uses: T1/S0 to S15 (alloc unit 0 & 1)
first datablock starts @ T1/S16 to S23 (alloc unit 2)

To identify if a disk is CP/M formated, read in the dir header & ID,
this is "CP/M PLUS" "65 2A" for the gcr based disks and "CP/M PLUS" "80 3D" for the 1581. If it is one of the gcr disks, read in the sector T1/S0 and check for the "CBM" boot signature, if this is present read the last byte of the boot sector to identify c128-single or double-sided disk. If "CBM" is absent you have a C64-single sided disk.


example CP/M dir from a 1581 disk (partially)
as you can see a file can have multiple dir entries (called extends) if the size exceeds the max. allocation possible with one entry (in this case 16K/entry).
The format of each individual 32byte long entry is as follows:

0U F1 F2 F3 F4 F5 F6 F7 F8 T1 T2 T3 EX S1 S2 RC   .FILENAMETYP....
AL AL AL AL AL AL AL AL AL AL AL AL AL AL AL AL   ................

0U = User Number. 0-15 ($00 - $0F)
         if this byte is $E5 => deleted or free entry
Fn - Filename (7bit ascii)
Tn - filetype. (7bit ascii)
       Bit7 (upmost) bit has special functions:
       If set in T1 -> the file is marked read-only
       T2 is set -> the file is marked as system-file (hidden)
       T3 is set -> archive attribute (reset when the file is modified)
EX - Extendnumber, lower byte - range 0-31
S2 - Extendnumber, upper byte.
S1 - Last record byte count (not allways used)
RC - Record count (1 Record=128 Bytes) in this extend
the total # of recs. of this file is (EX & exm) * 128 + RC.
If the number is $80 this extend (entry) is full, and the file might continue with another entry.

AL - allocation pointers, if the total alloc unit count is smaller than 256 these are 8bit pointers, else 16bit pointers to the data. 0 means unallocated (free)

Special entries:
first byte (0U) -
$10 -$1F - password entry + user #
$20 - directory label
$21 - date time entry (every 4th spot holding date/time for the former 3 files - $60,$e0...)

Hydrophilic

#2
Excellent post, LokalHorst!  I would like to add that the problem with CP/M formats is that in order to decode them, you need to know the allocation unit size, the number of allocation units on the disk, the number of reserved sectors, and the maximum number of directory entries.  But this is not stored anywhere on the disk!  As much as I enjoy bashing Microsoft, I'll admit their FAT file system is superior because the boot sector tells you these things.

Anyway, as I recall, the C64 and single-sided C128 formats (1541/1571) use 1 kiByte allocation units and the double-sided C128 formats (1571/1581) use 2 kiByte allocation units.  (This is consistant with 16 kiByte size per extent in LokalHorst's example).

But knowing that is not enough, you also need to know the disk capacity.  The single-sided formats have approx. 170 kiByte capacity.  170 / 1 = 170 which is less than 256, so each 'block' in a directory entry is only 1 byte.  That is you can have 16 blocks in one entry.

For 1571 double-sided disks, capacity is approximately 340 kiByte. 340 / 2 = 170 which is less than 256, so each directory entry also has 16 blocks.

But for 1581 (double-sided) disks, capacity is approximately 800 kiByte.  800 / 2 = 400 which is more than 255, so each 'block' in a directory entry requires 2 bytes.  That is, each directory entry can hold 8 blocks.

You can read the CP/M directory block after block starting from track 1 sector 0, but you need to know when to stop!  Unfortunately, I don't remember the number of directory sectors for each format...

Update
Looking at C128 PRG, it is noted that C128 GCR disks (1541 and 1571 single-sided) do not use Track 1 Sector 5.  So you should skip that sector.  And also ignore Track 1 Sector 0 because it has the boot sector and is not part of the CP/M directory.

Also the C64 GCR (1541) format reserves the first 2 tracks.  So you would start reading the directory from Track 3 Sector 0.  Also C64 GCR formats do not use sectors >= 17.

Now, are we all confused?
I'm kupo for kupo nuts!

LokalHorst

#3
Thanks Hydro,

but your addons are all in my post (I admit a bit sluggish)
Mirkosoft wanted only to read the directory, and as far as i understood only from the official 4 commodore formats.
For the 1571 ss/ds gcr disks, it's actually 3 sectors per side which are not accessed/used for the CP/M filesystem - on side 0 this is T1/S0 the boot sector, T1/S5 should be an empty dir sector, but the drive ignores the link in the Bam pointing here, T18/S0 the BAM in native mode. For the double sided disks this repeats with T36/S0, T36/S05, T53/S0.
The difference (for CP/M's view) of the aforementioned formats is only the allocation unit size (I prefer Cluster) SS-1K, DS-2K and 64 vs. 128 dir entries.
So to sum it it a bit up:
C64 SS(orig. CP/M 2.2 for C64) - read sectors 0 to 7 on track 3 (8 sectors a 256byte = 2K = 64 x 32byte cp/m dir entries.

C128 SS - read the following 8 sectors: (T=track#, S=sector#)
T1/S10;T1/S15;T1/S20;T1/S4 (alloc unit 0)
T1/S9;T1/S14;T1/S19;T1/S3 (alloc unit 1)
2 x 4 x 256bytes = 2K = 64 x 32byte dir entries.

C128 DS - read the following 16 sectors:
T1/S10;T1/S15;T1/S20;T1/S4 (alloc unit 0)
T1/S9;T1/S14;T1/S19;T1/S3
T1/S8;T1/S13;T1/S18;T1/S2 (alloc unit 1)
T1/S7;T1/S12;T1/17;T1/S1
2 x 8 x 256bytes = 4K = 128 x 32byte dir entries.

1581 CP/M (the official commodore variant) - read the following 16 sectors (256byte logical addressing):
Track 1 sector 0 to 15
2 x 8 x 256bytes = 4K = 128 x 32byte dir entries.

for analysing CP/M dirs always the full dir-size has to be read. (depending on the format/disk-type)