0 1 2 3 4 5 6 7 8 9 A B C D E F +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | H A D F S |&00| | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ |Flg| Disk Structure Record | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
If Flg=&0D then &11 to &1F contain a disk structure record that describes the shape of the disk. The rest of sector 0 and 1 usually contain 6502 code to load the HADFS ROM from the disk.
18 19 1A 1B 1C 1D 1E 1F HADFS disks are identified +--+--+--+--+--+--+--+--+ by this string |DskID|Date |MaxSec|Flag| +--+--+--+--+--+--+--+--+
&18-&19: DskID Disk id - created pseudo-randomly when a new disk is created &1A-&1B: Date Date of creation: &1A b7-b3: day &1A b2-b0: (year-1981)DIV16 &1B b7-b4: (year-1981)MOD15 &1B b3-b0: month &1C-&1E: MaxSec Maximum number of sectors. (Last sector number) + 1.
&1E-&1F: Flag b15=0 Small Disks - 16bit Free Space Map b14: Don't overwrite disk with *INSTALL b13: Mount this drive as URD b12: Mount this drive as LIB b11: Mount this drive as CSD b10-b6: unused b5: Reserved for 16 sectors/track flag b4: Sectors 0-1 do not contain a DFS catalogue b3: Don't modify DFS catalogue b2: Partitioned disk b1: Split disk, eg 40*2 b0: Data disk
b15=1 Large Disks - 24bit Free Space Map b14: Don't overwrite disk with *INSTALL b13: Mount this drive as URD b12: Mount this drive as LIB b11: Mount this drive as CSD b10-b9: unused b8: Don't modify DFS catalogue b7-b0: MaxSec b16-b23
Small Disk Free Space Map: 20 21 22 23 24 25 26 27 28 29 2A 2B 2C ... EB EC ED EE EF F0 F1...FE FF +--+--+--+--+--+--+--+--+--+--+--+--+- - - - -+--+--+--+--+--+ - - -+---+ |Start| Len |Start| Len |Start| Len | |00 00|00| | Reserved | +--+--+--+--+--+--+--+--+--+--+--+--+- - - - -+--+--+--+--+--+ - - -+---+
Large Disk Free Space Map: 20 21 22 23 24 25 26 27 28 29 2A 2B 2C ... EB EC ED EE EF F0 F1...FE FF +--+--+--+--+--+--+--+--+--+--+--+--+- - - - -+--+--+--+--+--+- - - -+--+ | Start | Length | Start | Length | |00 00 00| | Reserved | +--+--+--+--+--+--+--+--+--+--+--+--+- - - - -+--+--+--+--+--+- - - -+--+
The free space map is terminated by a Start=0. The last entry ends at &EB. With a full free space map, &EC/&ED/&EE contains a zero terminator.
Small Directory layout: &000 Dir. header &0C0 Entry 8 &180 Entry 16 &240 Entry 24 &018 Entry 1 &0D8 Entry 9 &198 Entry 17 &258 Entry 25 &030 Entry 2 &0F0 Entry 10 &1B0 Entry 18 &270 Entry 26 &048 Entry 3 &108 Entry 11 &1C8 Entry 19 &288 Entry 27 &060 Entry 4 &120 Entry 12 &1E0 Entry 20 &2A0 Entry 28 &078 Entry 5 &138 Entry 13 &1F8 Entry 21 &2B8 Entry 29 &090 Entry 6 &150 Entry 14 &210 Entry 22 &2D0 Entry 30 &0A8 Entry 7 &168 Entry 15 &228 Entry 23 &2E8 Entry 31
Large Directory layout: &000 Dir. header &116 Entry 8 &22E Entry 16 &021 Entry 1 &139 Entry 9 &251 Entry 17 &044 Entry 2 &15C Entry 10 &274 Entry 18 &067 Entry 3 &17F Entry 11 &297 Entry 19 &08A Entry 4 &1A2 Entry 12 &2BA Entry 20 &0AD Entry 5 &1C5 Entry 13 &2DD Entry 21 &0D0 Entry 6 &1E8 Entry 14 &0F3 Entry 7 &20B Entry 15
Directory header Small Directories: 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 12 13 14 15 16 17 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | Directory name |Parnt|NN|CC|Link |DskID|BB|UU|First|DBase| +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
Large Directories: 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 12 13 14 15 16 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | Directory name |xxxxx|NN|CC|xxxxx|DskID|BB|UU| First | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
17 18 19 1A 1B 1C 1D 1E 1F 20 +--+--+--+--+--+--+--+--+--+--+ | Link | Parent |xxxxxxxxxxx| +--+--+--+--+--+--+--+--+--+--+
SmallDir LargeDir &0A-&0B &1A-&1C Parnt: parent directory sector address &0C &0C NN: b0-b4: number of entries b5: reserved b6: long object names present. If long object names are present, the load and exec address fields are used to hold characters 11 to 16 of the object name and bytes &10 and &11 hold the filetype. b7: 0=small directories, 1=large directories &0D &0D CC: cycle number &0E-&0F &17-&19 Link: sector of next directory chunk, or zero &10-&11 &10-&11 DskID: disk ID &12 &12 BB: b0-b1: boot option b2-b3: reserved b4-b7: b8-b11 of user number &13 &13 UU: b0-b7 of user number &14-&15 &14-&16 First: sector of first directory chunk, or zero &16-&17 DBase: Base date for this small directory chunk
Directory entries Small directories: 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 12 13 14 15 16 17 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | Object name and attributes | Load Addr | Exec Addr | Len |Date |Sectr| +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
Large directories: 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 12 13 14 15 16 17 18 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | Object name and attributes | Load Addr | Exec Addr | Length | Sector | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
19 1A 1B 1C 1D 1E 1F 20 21 22 +--+--+--+--+--+--+--+--+--+--+ |CDate|MDate|MTime|User|Aux|At| +--+--+--+--+--+--+--+--+--+--+
&00 contains &00 if the entry is deleted. &00-&07 contain the attributes in bits 7: RWELRWEP &08 b7: 'D' attribute - entry is a directory
In small directories: &09 b7: (year-1981) bit 4 &14 b0-b2: b16-b18 of length b3-b7: day of object modification date &15 b0-b3: month of object modification date b4-b7: b0-b3 of (year-1981) of object modification date
In large directories: &19 b0-b2: b4-b7 of (year-1981) of object creation date b3-b7: day of object creation date &1A b0-b3: month of object creation date b4-b7: b0-b3 of (year-1981) of object creation date &1B b0-b2: b4-b7 of (year-1981) of object modification date b3-b7: day of object modification date &1C b0-b3: month of object modification date b4-b7: b0-b3 of (year-1981) of object modification date &1D b2-b7: hours of object modification time b0-b1: b3-b5 of minutes of object modification time &1E b5-b7: b0-b2 of minutes of object modification time b0-b4 seconds/2 of object modification time
Parent directory: +-----------+-----+-----------+-----+---------+-----+-----------+-----+-- |Object name| |Object name| |DirName | |Object name| | +-----------+-----+-----------+-----+---------+-----+-----------+-----+-- | +-----------------------<-+------------<-+ | | v | +---------+-----+-----+ | |DirName |Link |zero | | +---------+-----+-----+ | | | +---------<-+ | | | v | +---------+-----+-----+ | |DirName |Link |First| | +---------+-----+-----+ | | | | +---------<-+ +->-----+ | | v | +---------+-----+-----+ | |DirName |zero |First| | +---------+-----+-----+ | | | +->-----+
If the directory's parent directory entry is also in an extended directory, the Parent field should point to the parent directory's first chunk, pointed to by the parent directory's First field.
Double-sided floppy disks can also be set to C:H:S addressing, that is the sectors count along one track on side 0, then along the same track on side 1, and then back to the next track on side 0. This is called interleaved addressing. If there are more than 80 track per side, then the extra tracks continue in the same manner. HADFS defaults to sequential addressing.
HADFS determines if a floppy is sequential or interleaved by looking for the Free Space Map. If HADFS can't find the FSM using sequential addressing, it looks for it using interleaved addressing. If HADFS still can't find the FSM, the disk is not recognised as HADFS.
Drives 0 and 1 are the two physical drives that are accessed as drives 0/2 and 1/3 in DFS. Accessing drives numbered above 1 causes an OSWORD call for extra software to provide access to other drives. If there is no
driving software for drives 2 onwards, then the error Drive x not present
is given if an attempt to access it is made. The OSWORD call for the extra
drives is:
A=90 (&5A) XY+0: 0 Check for these values XY+1: 6 in these two locations. XY+2: \ XY+3: \ Address XY+4: / XY+5: / XY+6: \ \ XY+7: } Start sector \ Four-byte XY+8: / / sector address XY+9: Drive number / XY+10: Number of sectors XY+11: Call type and return code
Call types: 1 write sectors 2 read sectors 3 request drive info 4 format 5 park heads (do not claim) &80 user read sectors &81 user write sectors
To provide access to extra drives, you must intercept the OSWORD routine and check for OSWORD 90. You must only claim the call if the first two bytes are &00,&06 and the drive number is the drive you are supporting, and the call type is less than 128. Calls 128 and above are translated by HADFS into either an OSWORD &7F call or another OSWORD 90 call.
Calls 1 and 2 read and write the supplied number of sectors using the address in memory and the sector start. HADFS usually reads and writes a between 8 and 64 sectors at a time, but you should be able to cope with the full range.
Call 3 should return the total number of sectors on the drive in XY+6 to XY+8 (&000000 meaning &1000000). If the number of sectors in XY+10 is not zero, the call should do a sector read, as call 2.
Call 4 reserved for formatting disks.
Call 5 is issued when a *BYE comand is used. This should not be claimed,
as it should be passed on to other driving routines.
Calls &80 and &81 are translated by HADFS into the required calls to read either the floppy drives by calling OSWORD &7F or an external drive by calling OSWORD 90. They should not be claimed or recognised in any way by the driving routines.
A return code of 0 indicates that all is well and the operation was provided. A return code of 1 to 7 (ie unchanged from the call type) indicates that the drive is not present. Return codes of 8 and above are used as disk error numbers. Some of these are: &08 Clock error &0A Late DMA &0C CRC error in ID &0E CRC error in data &12 Drive read only &14 Track zero not found &16 Write error &18 Sector not found
Calls &80 and &81 translate an unchanged return code into: &FE Drive not present
Error &10, Drive not ready, should never be returned. The routine should
retry until the drive is ready, or another error is returned. Other return
codes are reported as Disk error XX.
Selection of screen memory is taken care of by the HADFS code, and so the only i/o address supplied will be &FFFFxxxx. Addresses in the language processor should be taken care of by the driving routine using the Tube communication routines installed by the Tube code at &406. If there is no Tube present, then the supplied addresses will always be in the i/o processor, ie &FFFFxxxx.
*OPT7,1 is set and HADFS assumes
that there is only one floppy drive and accesses to drive 1 will be made
by calling OSWORD 90, above. The first time an access to drives 0 to 7 is
made, it is made through OSWORD 90, above. If this is claimed, then all
further accesses to that drive are made through OSWORD 90 until the next
*HADFS, *MOUNT, *I AM or *BYE. Otherwise, accesses to drive 0 to 7 are
made with internal drivers. Drives 0 and 1 access the floppy drive
through OSWORD &7F. To force accesses to drives 0 to 7 to use external
drivers via OSWORD 90, *OPT7,<drive> can be used. To make drive access
return to using internal drivers use *OPT6,<drive>. *OPT0 resets all the
*OPT6 and *OPT7 settings.
*OPT5 and the *OPT6,1 or *OPT7,1 setting. These can be shown
with *STATUS HADFS. When running on a BBC B, HADFS provides a *STATUS
command to display the settings set by *OPT5, 6 and 7. It also shows
the current date setting.
HADFS stores the following information in it's CMOS byte at ROMnumber+30:
bits 0-3: unused
bits 4-5: 5-(number of channels)
bit 6 : Drive 1 external (*OPT 7,1)
bit 7 : unused
The top four bits are inverted after reading and before writing, so a CMOS value of &00 gives 5 channels and internal drive 1.
*MOUNT with no parameter, or after startup, HADFS needs to
decide what drive to use. It does this by examining each disk present and
then calling three OSBYTE calls to see if there is some software that
wants to change the default drive. Normally, HADFS defaults to drive 0 if
not told what drive to use explicitly.
The OSBYTE calls are: A=90, X=6, Y=64 Look for default drive A=90, X=6, Y=65 Look for default library drive A=90, X=6, Y=66 Look for default user drive
When there is a file access after a *MOUNT or a startup, HADFS checks
the disk flags on each drive from 31 down to 2. Then, OSBYTE 90,6,64 is
called to see if there is a default drive to set the CSD to. If there is,
the URD and CSD are set to this. OSBYTE 90,6,65 is then called to see if
there is a default drive for the Library directory. If there is, then the
directory $.Library is looked for on that drive. If there isn't, then
the LIB drive is set to the CSD drive (which may have been set by OSBYTE
90,6,64), and $.Library looked for there.
If the OSBYTE call is not claimed, then the MOS sets the X register to &FF. If some software claims the OSBYTE call and sets the X register to a drive number, this will be in the range &00 to &1F for drive :0 to :V. HADFS checks bit 7 of the returned X to see if the OSBYTE call has returned a drive number.
This means that lower numbered drives have mount priority over higher number drives, and software responding to OSBYTE 90 has priority over any disks present.
The program Intern/s demonstates various OSBYTE call claiming when creating a drive in sideways RAM. It also shows how to call the Tube code for communicating with a second processor.
Channels 27 to 29 are only available if the memory is available. *OPT5
can be used to limit the number of channels available and the amount of
memory used. *OPT5,0 tells HADFS to use as little memory as possible. If
another ROM reserves sufficient absolute workspace with service call 1 (eg
DFS), then HADFS will use all the memory available. Channel 26 is always
used for input, as its buffer is also used for other purposes, and keeping
channel 26 input-only means that HADFS doesn't have to keep saving the
buffer to disk.
The lowest value that PAGE can be moved to is: &1700 Loads/Saves/up to 5 channels open &1600 Loads/Saves/up to 4 channels open &1500 Loads/Saves/up to 3 channels open &1400 Loads/Saves/up to 2 channels open &0E00 No access available
*I
AM BOOT command is issued, which abandons any open channels, mounts the
default user drive and starts any auto-start sequence.
Pressing Ctrl-CapsLock-H-Break will disable HADFS in the same way as
*FX90,6,1.