7 HADFS technical information

General
Sectors 0-1 contains a DFS catalogue. On a data 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 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 |MaxSc|Flags|
 +--+--+--+--+--+--+--+--+

DskID: Disk id - created pseudo-randomly when a new disk is created Date:  Date of creation, bit 4 of (year-1981) is in b0 of byte &1A MaxSc: Maximum number of sectors. (Last sector number) + 1. Flags: b0: Data disk
	b1: Split disk, eg 40*2
	b2: Partitioned disk
	b3: Don't modify DFS catalogue
	b4: Sectors 0-1 do not contain a DFS catalogue
	b5: Reserved for 16 sectors/track flag
	b6-b15: unused.

 20 21 22 23 24 25 26 27 28  ....  EB EC ED EE EF F0 F1 F2  .....  FE FF
 +--+--+--+--+--+--+--+--+- - - - -+--+--+--+--+--+--+--+--+- - - -+--+--+
 |Start| Len |Start| Len |            |     |     |       Reserved       |
 +--+--+--+--+--+--+--+--+- - - - -+--+--+--+--+--+--+--+--+- - - -+--+--+

The free space map is terminated by a Start=&0000. The last entry would be at &E8-&EB. With a full free space map, &EC/&ED contains a zero terminator.

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

Directory header:
  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|xx|xx|
 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 Parnt:	parent dir sector address
 NN:	b0-b4: number of entries
	b5-6:  entry size flag - 0: 24 bytes per entry, 1-3: undefined.
	b7:    long filenames present. If long filenames are present, the load and exec address fields are used to
	hold characters 11 to 18 of the filename.
CC:	cycle number
Link:	sector address of next dir chunk, or zero
DskID:	disk ID
BB:	bits 0-1: boot option
	bits 2-3: reserved
	bits 4-7: b8-b11 of user number
UU:	b0-b7 of user number
First: sector address of first dir chunk, or zero
xx:	unused

Directory entry:
  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F 10 11 12 13 14 15 16 17
 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 |   Filename and attributes   | Load Addr | Exec Addr | Len |Date |Sectr|
 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

Byte &00 contains &00 if the entry is deleted.
Bytes &00-&07 contain the attributes in bits 7: RWELRWEP
Byte 8 bit 7: 'D' attribute - entry is a directory
Byte 9 bit 7: (year-1981) bit 4
Byte &14	   b0-b2: b16-b18 of length
	   b3-b7: day of file creation date
Byte &15	   b0-b3: month of file creation date
	   b4-b7: b0-b3 of (year-1981) of file creation date

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 always contain: "HADFS",&00.

Sector Addresses
A sector address is 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. Current versions of HADFS only use sectors from &000000 to &00FFFF.

Sectors are always numbered from zero upwards. Sectors 0 and 1 are reserved for the DFS catalogue, and sectors 70 to 73 for the free space map and root directory. The sectors count upwards on one side of the disk, then upwards on the other side. On a DFS formatted disk (10 sectors/track), the second side always starts at sector 800. If you format a disk with less 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. If you format a disk with more than 80 tracks, sectors after 1599 are mapped as follows:

	Sectors 1600-1609	Track 81, Side 0, sectors 0-9
	Sectors 1610-1619	Track 81, Side 1, sectors 0-9
	Sectors 1620-1629	Track 82, Side 0, sectors 0-9
	Sectors 1630-1639	Track 82, Side 1, sectors 0-9
	etc.
That is, after sector 1599, the sector numbering goes upwards track by track, on alternative sides. Disks can usually be formatted to a maximum of 82 tracks. On an ADFS formatted disk (16 sectors/track), the sectors are numbered similarly. The second side starts at sector 1280, sectors larger than 2560 count upwards from track 81 on alternative sides.

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 &0000. Each chunk's First field points to the sector of the first chunk, the first chunk's First field being &0000.

Parent directory:
 +---------+-----+---------+-----+---------+-----+---------+-----+--
 |Filename |     |Filename |     |DirName  |     |Filename |     |
 +---------+-----+---------+-----+---------+-----+---------+-----+--
					      |
 +-----------------------<-+---------------<-+
 |			    |
 v			    |
 +---------+-----+-----+   |
 |DirName  |Link |&0000|   |
 +---------+-----+-----+   |
	      |             |
 +---------<-+             |
 |                         |
 v                         |
 +---------+-----+-----+   |
 |DirName  |Link |First|   |
 +---------+-----+-----+   |
	      |     |	    |
 +---------<-+     +->-----+
 |			    |
 v			    |
 +---------+-----+-----+   |
 |DirName  |&0000|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. 

External virtual 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	Ram disk or fourth physical drive
		  4	Hard disk drive
		  5-G	unallocated
		  I	Internal rom files
		  J-L	unallocated
		  M	Memory (ram) disk
		  N-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 maximum of eight 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).

Call 4 is used to format a disk. The user will already have been promptedGo? (Y/N). As you format, you should print an updating display Foratting D:XXXX, similarly to the *FORM command when formatting floppies.

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.

Call with XY+1 set to 37 used to find external files. Entry and return parameters not yet defined.

Keyboard links and *OPT6
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 *OPT6 defaults to 1 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 drive 0 is made, it is made through OSWORD 90, above. If this is claimed, then all further accesses to drive 0 are made through OSWORD 90. Otherwise, accesses to drive 0 are made to the floppy drive through OSWORD &7F. To force accesses to drive 0 to use OSWORD 90, *OPT6,2 can be used, and*OPT6,3 to force drive 0 to use OSWORD &7F. If there is no supporting routine, then it will fall back to OSWORD &7F anyway.

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,0 or *OPT6,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 and 6. 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
	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
When HADFS needs to decide what drive to use, after a *MOUNT with no parameter, or after startup, three OSBYTE calls are used 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 needs to decide what drive to use. 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. An 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.

When a *I AM command is issued, OSBYTE 90,6,66 is called to see if there is a drive to look for user directories on. If there is not, then the*I AM command looks on the CSD drive. The CSD drive could already have been set by OSBYTE 90,6,64.

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.

The program S/Intern 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. 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
With HADFS versions before 0.45, lowering PAGE will corrupt the date set by *HSETDATE. *HSETDATE will corrupt anything that previously corrupted the date. From version 0.45 onwards, the time and date is stored at &3D8-&3DF.
Memory corruption
The OSWORD &7F call on Watford DFS corrupts some memory workspace memory even when it belongs to someone else. The memory corrupted is used by HADFS when active to store information about channels 28 and 29. You can use *OPT5,3 to restrict HADFS to using only channels 25, 26 and 27 to avoid this problem.

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 aCtrl-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*HAD-OFF or *FX90,6,1.