8 HADFS technical

information

General

Sectors 0-1 usually a DFS catalogue. On a data disk or a dual-boot disk, sectors 2-69 contain data, and the DFS !Boot file is embedded in the DFS catalogue. On a system disk, sectors 2-3 contain the DFS !Boot file; sectors 4-5 contain the DFS SPARE or ReBoot file; sectors 6-69 contain the HADFS ROM image. Sector 70 contains the disk name and free space map. Sector 71-73 contains the root ($) directory. All names are padded with spaces.

Sector 0-1

Sectors 0 and 1 usually contain a DFS catalogue with a boot file to select HADFS. The first six bytes of sector zero usually contain: "HADFS",&00.

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.

Sector 70

0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 12 13 14 15 16 17 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | Disk name | &00,(C)JGH,&00 | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

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.

Directories

There are two types of directory. Large disks always use Large Directories. Small Disks default to Small Directories, but can use Large Directories.

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

Extended Directories

To be able to store more than 31 entries in a directory, a directory can be extended by stringing together two or more directory chunks, where a directory chunk is three sectors containing directory information. The parent directory's entry for the directory points to the sector of the first chunk. The directory chunks' Link field points to the sector of the next chunk, the last chunk's Link field being zero. Each chunk's First field points to the sector of the first chunk, the first chunk's First field being zero.

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.

Sector Addresses

HADFS uses 256-byte sectors. Sectors are addressed by a four-byte value made up as &ddssssss where dd is the drive number and ssssss is the sector on that drive. All HADFS functions use four-byte sector addresses. Small disks use 16-bit sector addresses, &000000 to &00FFFF, allowing a maximum disk size of 16M. Large Disks use 24-bit sector addresses, &000000 to &FFFFFF, allowing a maximum disk size of 4G.

Mapping to physical disk sectors

Floppy disks are usually addressed H:C:S, that is, the sectors count upwards on one side of the disk, then upwards on the other side. This is called sequential addressing. On a DFS formatted disk (10 sectors/track), the second side always starts at sector 800. If you format a disk with fewer than 80 tracks, then there will be a gap just before sector 800, which must be reflected by a gap in the free space map, and the Split Disk flag must be set in the disk flags.

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.

External drives

Valid drive numbers are 0-9, A-V, giving 31 drives. Current allocation is: Drive 0 First physical drive 1 Second physical drive 2 Third physical drive 3 Fourth physical drive 4 First hard disk drive 5 Second hard disk drive 6 Third hard disk drive 7 Fourth hard disk drive 8-G unallocated I Internal ROM files J-L unallocated M GoMMC RAM disk N-Q unallocated R RAM disk S-V unallocated

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.

Keyboard links, *OPT6 and *OPT7

On the BBC B and B+, keyboard link 2 is used to signify if a second drive is present. If this link is made, then *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.

Master CMOS configuration

On the Master series, some information is saved in HADFS's CMOS byte at ROMnumber+30. The information stored there is the number of channels set with *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.

Changing default drives

After a *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.

HADFS memory use

HADFS uses the following pages of memory: &0E00 Channel 25 buffer &0F00 Channel 26 buffer/FSM buffer/used for last few bytes of LOAD &1000 HADFS information &1100\ &1200 } Current directory &1300/ &1400 Channel 27 buffer &1500 Channel 28 buffer &1600 Channel 29 buffer private w/s: HADFS information when HADFS not selected.

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

Break and Reset

Most of HADFS's information is preserved over a Break or Ctrl-Break. All channels remain open and the CSD, URD and LIB remain selected. On a Ctrl-Break, any open channels are abandoned. On a Shift-Break, a *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.