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 +---+---+---+---+---+---+---+---+ |Flg| Disk Structure Record | +---+---+---+---+---+---+---+---+
If Flg=&0D then &11 to &17 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. On a disk with multiple paritions, sectors 0 and 1 will hold information about the non-HADFS partition.
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-b9: unused b8: Don't modify sectors 0 and 1 b7-b3: unused 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 sectors 0 and 1 b7-b0: MaxSec b16-b23
Small Disk Free Space Map: 20 21 22 23 24 25 26 27 28 29 2A 2B 2C ... F7 F8 F9 FA FB FC FD 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 ... F7 F8 F9 FA FB FC FD 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 &F7. With a full free space map, &F8/&F9/&FA 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 &0C0 Entry 6 &180 Entry 12 &240 Entry 18 &020 Entry 1 &0E0 Entry 7 &1A0 Entry 13 &260 Entry 19 &040 Entry 2 &100 Entry 8 &1C0 Entry 14 &280 Entry 20 &060 Entry 3 &120 Entry 9 &1E0 Entry 15 &2A0 Entry 21 &080 Entry 4 &140 Entry 10 &200 Entry 16 &2C0 Entry 22 &0A0 Entry 5 &160 Entry 11 &220 Entry 17 &2E0 Entry 23
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| Aux | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
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 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | Directory name |xx xx|NN|CC| Aux |DskID|BB|UU| First |00| +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
18 19 1A 1B 1C 1D 1E 1F +--+--+--+--+--+--+--+--+ | Link |00| Parent |00| +--+--+--+--+--+--+--+--+
SmallDir LargeDir &0A-&0B &1C-&1E Parent: 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 &18-&1A 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 &0E Aux: b0-b3: reserved b4-b7: b8-b11 of auxilary user number &17 &0F Aux: b0-b7 of auxilary user number
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 +--+--+--+--+--+--+--+ |00|MDate|MTime|CDate| +--+--+--+--+--+--+--+
&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 &0D b7-b6: (year-1981) b6-b5 b5: b7-b5 of Load address &14 b2-b0: b18-b16 of length b7-b3: day of object modification date &15 b3-b0: month of object modification date b7-b4: b3-b0 of (year-1981) of object modification date
In large directories: &19 unused, &00 &1A b2-b0: b7-b4 of (year-1981) of object modification date b7-b3: day of object modification date &1B b3-b0: month of object modification date b7-b4: b3-b0 of (year-1981) of object modification date &1C b4-b0: seconds/2 of object modification time b7-b5: b2-b0 of minutes of object modification time &1D b2-b0: b5-b3 of minutes of object modification time b7-b3: hours of object modification time &1E b2-b0: b6-b4 of (year-1981) of object creation date b7-b3: day of object creation date &1F b3-b0: month of object creation date b7-b4: b3-b0 of (year-1981) of object creation date
All the sector entries in Big Directories are three bytes followed by a zero byte, to leave room for future extension of sector numbers to four bytes.
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.
Drives 0 and 1 are the two floppy 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 5 (ie unchanged from the call type) indicates that the drive is not present. Return codes of 6 and above are used as disk error numbers. These are: &06 Bad block (IDE error &80) &08 Clock error &0A Late DMA &0C CRC error in ID (IDE error &01) &0E Data CRC error (IDE error &40) &10 reserved &12 Drive read only &14 Track zero not found (IDE error &02) &16 Write error &18 Sector not found (IDE error &10) &1A Media change request (IDE error &08) &1C Abort (IDE error &04) &FE Disk/drive not present (IDE error &20)
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.
Acorn DFS 0.90 has a bug in that is responds to all OSWORD calls numbered
&80 and higher. This means that when HADFS looks for a default drive after
*MOUNT
or Shift-Break, when it tests the GoMMC drive DFS corrupts the HADFS
workspace. To avoid this, if DFS 0.90 is present HADFS disables the GoMMC
driver.
Due to the way of testing for DFS 0.90 the GoMMC driver is also disabled on a BBC B if DFS is actually completely absent. To enable the GoMMC driver on a BBC B which has no DFS present set keyboard link 2.
*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.
*OPT6/7
setting is saved in HADFS's CMOS byte at ROMnumber+30. The
*OPT6/7,0
setting is store in bit 7 and the *OPT6/7,7
setting in bit 0.
The current setting can be shown with *STATUS HADFS
. When running on a BBC
B, HADFS provides a *STATUS
command to display the settings set by *OPT6
and *OPT7
. It also shows the current date setting.
HADFS prior to v5.65 only stores the *OPT6/7,1
setting in bit 6.
*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 MkIntern 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.
On the BBC channel 25 is always used for input, as its buffer is also used for other purposes, and keeping channel 25 input-only means that HADFS doesn't have to keep saving the buffer to disk. If DFS is absent on a BBC, then channel 26 becomes available.
The lowest value that PAGE can be moved to on a BBC is: &1700 Loads/Saves/up to 4 channels open &1600 Loads/Saves/up to 3 channels open &1500 Loads/Saves/up to 2 channels open &1400 Loads/Saves/only 1 read-only channel open &1000 Loads/Saves/only 1 read-only channel open - but loading to &1000 will overwrite directory buffer, and reading a directory will overwrite memory at &1000 &0E00 No access available - one load to &E00 can occur, but then workspace will be overwritten and no further access is available
*I AM
BOOT
command is issued, which abandons any open channels, mounts the
default user drive and starts any auto-start sequence.