www.riscos.com Technical Support:Programmer's Reference Manual

FileCore

Introduction

FileCore is a filing system that does not itself access any hardware. Instead it provides a core of services to implement a filing system similar to ADFS in operation. Secondary modules are used to actually access the hardware.

ADFS and RamFS are both examples of such secondary modules, which provide a complete filing system when combined with FileSwitch and FileCore.

The main use you may have for FileCore is to use it as the basis for writing a new ADFS-like filing system. Because it already provides many of the functions, it will considerably reduce the work you have to do.

Overview

FileCore is a filing system module. It provides all the entry points for FileSwitch that any other filing system does. Unlike them, it does not control hardware; instead it issues calls to secondary modules that do so.

Similarities with FileSwitch

This concept of a parent module providing many of the functions, and a secondary module accessing the hardware, is very similar to the way that FileSwitch works. There are further similarities:

there is a SWI, FileCore_Create, which modules use to register themselves with FileCore as part of the filing system

this SWI is passed a pointer to a table giving information about the hardware, and entry points to low-level routines in the module

FileCore communicates with the module using these entry points.

When you register a module with FileCore it creates a fresh instantiation of itself, and returns a pointer to its workspace. Your module then uses this to identify itself on future calls to FileCore.

Adding a module to FileCore

When you add a new module to FileCore, there is comparatively little work to be done. It needs:

low-level routines to access the hardware

a * Command that can be used to select the filing system

any additional * Commands you feel necessary - typically very few

a SWI interface.

The SWI interface is usually very simple. A typical FileCore-based filing system will have SWIs that functionally are a subset of those that FileCore provides. You implement these by calling the appropriate FileCore SWIs, making sure that you identify which filing system you are. RamFS implements all its SWIs like this, ADFS most of its. So unless you need to provide a lot of extra SWIs, you need do little more than provide the low-level routines that control the hardware.

Technical details

FileCore-based filing systems are very like ADFS in operation and appearance (since ADFS is itself one). However, there is no reason why you need use FileCore only with discs; indeed, RamFS is also a FileCore-based filing system. The text that follows describes FileCore in terms of discs, disc drives, and so on. We felt you would find it easier to use than if we had used less familiar terminology - but please remember you can use other media too.

Disc formats

Logical layout

This table shows the logical layout of 'perfect' ADFS formats for floppy discs:

Format

Map

Zones

Directories

Boot block

L

Old

--

Old

No

D

Old

--

New

No

E

New

1

New

No

F

New

4

New

Yes

(The boot block is needed for F format floppies to specify which zone holds the map.)

Physical layout

A head value of 1 means that the sides are sequenced, whereas a head value of 2 means that they are interleaved:

On a sequenced disc the logical order of tracks is those on one side of the disc, followed by those on the other side. For example, with 8 tracks:

On an interleaved disc the logical order of tracks alternates between sides of the disc. For example, with 8 tracks:

Track layout

A track is laid out as follows:

Due to mechanical variation in speed the time between the start and end varies, which is why there are gaps - they 'absorb' the speed variations. So, in words:

gap4b is the gap between the mechanicalindex pulse and the magneticindex mark

ID is the magnetic index mark

gap1 is the gap between the index mark and the first sector

sector is a sector (see below)

gap3 is the gap between sectors

gap4a is the gap between the last sector and the index pulse.

The magnetic index mark and the preceding gap4b are optional. Where they are absent, gap1 is therefore the gap between the mechanical pulse and the first sector.

You should never rely on the presence or absence of the magnetic mark.

The size of gap1 and gap3 change between formats, whilst the other sizes remain constant. This table shows those gap sizes that vary (in bytes) and the sector skew (in sectors) of 'perfect' ADFS formats:

Format

Gap 1 side 0

Gap 1 side 1

Gap 3

Sector skew

L

42

42

57

0

D

32+271

32+0

90

0

E

32+271

32+0

90

0

F

50

50

90

2

Sector layout

A sector is laid out as follows:

gap2 is fixed due to hardware limitations; it is there to accommodate variations in hardware (different spin speeds etc)

Each of sector ID and sector data have a preamble of null bytes, a synchronisation pattern, an identification byte (which says what sort of information follows: ID or Data), and the data itself (ID or data).

The reason the ID is separated from the data is that during sector writing the ID is read to determine which bit of the disc is currently going under the head, then the drive is switched to writing - which takes some time - and then a whole section of data is written (ie the sector data).

Note: The 'perfect' disc formats referred to in this section may not always be attainable. For example, the 710/711 controllers cannot achieve a gap1 of more than 255 bytes, and hence use a good alternative. See also FileCore_DiscFormat and ADFS_VetFormat for a description of the process used to negotiate an attainable format.

Maps

A disc has a section of information, called a map, which controls the allocation of the disc to the files and directories. There are two types of maps used in RISC OS 3: the old maps used by L and D formats, and the new maps used by later formats:

Map

Information stored

Compaction required

Recovery story

Old

Free space

Yes

From directories

New

Space allocation

No

Two copies stored

New map discs have the following advantages over old map discs:

Files need not be stored contiguously, so you don't need to compact the disc. (However, FileCore does try to create new map files in one block, and will also try to merge file fragments back together again if it is compacting a zone of the disc.)

The disc map has no limit on size or number of entries, so 'Map full' errors do not occur.

The map keeps a record of defects when the disc is formatted, so omits defective sectors.

Defects are kept as objects on the disc, so they don't need to be taken into account when calculating disc addresses, and can be mapped out without reformatting.

Old maps

Old maps have the following format:

Name

Bytes

Meaning

FreeStart

82 × 3

Table of free space start sectors

Reserved

1

Reserved - must be zero

OldName0

5

Half disc name (interleaved with OldName1)

OldSize

3

Disc size in (256 byte) sectors

Check0

1

Checksum on first 256 bytes

FreeLen

82 × 3

Table of free space lengths

OldName1

5

Half disc name (interleaved with OldName0)

OldId

2

Disc id

OldBoot

1

Boot option (as in *Opt 4,n)

FreeEnd

1

Pointer to end of free space list

Check1

1

Checksum on second 256 bytes

The 82 three byte entries in the FreeStart and FreeLen tables are in units of 256 bytes. The entries are sorted low addressed free areas first. Contiguous free areas will have been merged together.

The full disc name is the joining together of the bytes in OldName0 and OldName1. The name is interleaved, with OldName0 providing the first character, OldName1 the second, and so on.

OldId is the disc's Id to identify when the disc has been modified.

If an old map does not end at a sector boundary, then it is padded with null bytes to the end of the sector. The sector immediately following the old map always holds the start of the root directory; see the chapter entitled Directories.

Calculating Check0 and Check1

These are checksums of the previous bytes in the map. They are calculated using repeated 8-bit ADCs on the bytes of the relevant map block, starting with a value 0:

If R0 is the accumulated checksum, then it starts at 0, and each byte is added as follows:

Note that the check byte itself isn't included in the checksum; its value equals the checksum of the previous bytes.

New maps

A disc using a new map is divided into a number of zones, each of which is a contiguous section of the disc. The zones are numbered 0 upwards, so if there are nzones zones on a disc, the zone numbers are 0, 1, ..., nzones - 2 and nzones - 1 (ie zone 0 contains the lowest numbered sectors on the disc, and zone nzones - 1 the highest numbered sectors).

The map is located at the beginning of zone nzones/2 (rounded down). Hence, the map will sit at the beginning of the middle zone for discs with an odd number of zones, and the zone higher than the middle for discs with an even number of zones (examples: if nzones = 7, the map is at the start of zone 3, which has 3 zones before it and after it; if nzones = 8 the map is at the start of zone 4, which has 4 zones before it and 3 after it).

The map is nzones sectors long: each sector of the map is known as a map block, and controls the allocation of a zone of the disc. The first map block controls zone 0, the second controls zone 1, and so on.

As an example of how to use the logarithmic values, if the sector size was 1024, this is 210, so at offset 0 you would store 10.

You can use a disc record to specify the size of your media - this is how RamFS is able to be larger than an ordinary floppy disc.

The lowsector and disctype fields are not stored in the disc record kept on the disc, but are returned by FileCore_DescribeDisc.

Allocation bytes

The allocation bytes make up the section of the map block which controls the allocation of a zone. Together, the allocation bytes from all map blocks control the allocation of the whole disc. Each bit corresponds to an allocation unit on the disc. The size of the allocation units is defined in the disc record by log2bpmb, and so must be a power of two bytes. An allocation unit is not necessarily one sector - it may be smaller or larger.

Not only must space be logically mapped in whole allocation units; it must also be physically allocated in whole sectors. Consequently, the smallest unit by which allocation may be changed is the larger of the sector size and the allocation unit. This unit is known as the granularity.

A disc is split into a number of disc objects, each of which consists of one or more fragments spread over the surface of the disc. Fragments need not be held in the same zone, and their size can vary by whole units of granularity. Fragments have a minimum size, which is explained below.

Three disc objects are special, and contain:

the bad sectors (for a perfect disc, this disc object will not be present)

the boot block, map and root directory

the free space.

All other disc objects contain either a directory (optionally with small files held within that directory), or one or more files that are held in a common disc object. For a description of how disc objects can contain more than one object, see the chapter entitled Internal disc addresses and the Directories.

The allocation bytes are treated as an array of bits, with the lsb of a byte coming before the msb in the array.

The array is split into a series of fragment blocks, each representing a fragment. The format of a fragment block is as follows:

(idlen is defined in the disc record.)

Since each bit in the array corresponds with an allocation unit on the disc, the length of the fragment block (in bits) must be the same as the size of the fragment (in allocation units). The stream of 0 bits are used to pad the fragment block to the correct length, and the 1 bit to terminate the fragment block.

There are two fragment ids with special meanings:

A fragment id of 1 represents the object which contains all bad sectors, and the spare piece of map which hangs over the real end of the disc.

A fragment id of 2 represents the object which contains the boot block, the map, and the root directory.

A fragment id for a free space fragment is the unsigned offset, in bits, from the beginning of its fragment block to the beginning of the next free space fragment block in the same map block (or 0 if there are no more).

The chain hence always runs from the beginning of the map block to the end.

The offset to the first free space fragment block is given by the FreeLink fragment block in the map block's header. Because that fragment block is 2 bytes long, and must have a terminating 1 bit, idlen cannot be greater than 15.

A fragment id for an allocated fragment is a unique identifier for the disc object to which that space is allocated. Any other fragments allocated to the same disc object will have the same fragment id.

The following deductions can be made:

The smallest fragment size on a disc is:

(idlen+1) × allocation unit - rounded up to the nearest unit of granularity

because a fragment block cannot be smaller than idlen+1 bits (the fragment id, and the terminating 1 bit).

idlen must be at least:

log2secsize + 3 - ie log2 (sector size in bits)

to ensure that it is large enough to hold the maximum possible bit offset to the next free fragment block.

The maximum number of fragment ids in a map block (and hence disc objects in a zone) is:

This value is smaller for Zone 0 than for other zones, because it has a copy of the disc record, and hence fewer allocation bytes:

The value for zones other than Zone 0 is - for a given disc - always the same, and is known as the ids per zone. It is easiest to calculate using fields from the disc record:

((1 << (log2secsize + 3)) - zone_spare) / (idlen + 1)

The allocation unit cannot be so small as to require more than 15 bits to represent all the fragment ids possible, ie:

(ids per zone×nzones) 215

since the fragment id cannot be more than 15 bits long.

An object may have a number of fragments allocated to it in several zones. These fragments must be logically joined together in some way to make the object appear as a contiguous sequence of bytes. The naïve approach would be to have the first fragment on the disc be the first fragment of the object. New map discs do not do this. The first fragment in an object is the first fragment on the disc searching from zone (fragment id / ids per zone) upwards, wrapping round from the disc's end to its start. Any subsequent fragments belonging to the same disc object are joined in the order they are found by this search.

Object 2, being the object which carries the map with it, is special. It is always at the beginning of the middle zone, as opposed to being at the beginning of zone 0.

Maximum disc sizes

As observed above, there are a number of limitations placed on discs by new maps, depending on your choice of various parameters. The table below gives some idea of the theoretical maximum disc sizes that can be supported, depending on the sizes of the allocation unit and of the sectors:

Allocation unit

512 byte secs

1024 byte secs

256

up to 124Mb

up to 127Mb

512

up to 249Mb

up to 255Mb

1024

up to 503Mb

up to 511Mb

2048

up to 1007Mb

up to 1023Mb

In fact, other limitations in FileCore mean that discs can be no larger than 512Mbytes.

Calculating disc addresses

To translate an allocation bit in the map to a disc address, take the allocation bit's bit offset from the beginning of the bit array (ie the concatenation of all allocation bytes) and multiply this offset by the bytes per map bit (this multiplication is equivalent to shifting the offset left by log2bpmb, which is why the log2 value is stored in the disc record).

This result is the byte offset across the disc of the beginning of the section of the disc which corresponds to the given map bit. This quantity can be passed to FS_DiscOp SWIs directly.

Calculating CrossCheck

These bytes provide a means to check that the set of zones match each other. To check the set matches, these bytes are exclusive ORd (EOR) with each other: the answer must be &FF. They are modified whenever more than one zone map is modified. (The algorithm is not important, just so long as the bytes of the changed maps change and that the EOR of all these bytes remains at &FF).

Calculating ZoneCheck...

This, as described previously, is a check byte on a given zone sector. Below are some code fragments you can use to calculate this value, using either C or assembler:

Disc addresses

In reading the following description, you should take special care over the difference between an object (ie a single file or a directory) and a disc object (ie a logical group of fragments on a new map disc, that may contain one or more objects).

FileCore uses two different types of disc address.

The first is a normal physical disc address, giving the offset in bytes of data from the start of the disc.

The second is an internal format used with new map discs, that specifies an object in terms of its fragment id, and its offset in sectors within that fragment.

This is how a single disc object can hold many objects. The internal address of each object within the disc object will have the same fragment id, but a different offset within that fragment.

Physical disc addresses

The physical disc address of a byte gives the number of bytes it is into the disc, when it is read in its sequential order from the start. To calculate the physical disc address of a byte you need to know:

its head number h

its track number t

its sector number s

the number of bytes into the sector b

the number of heads on the drive H

the number of sectors per track S

the number of bytes per sector B

the number of defective sectors earlier on the disc x (for old map hard discs only - use zero for old map floppy discs or new map discs)

You can use this formula for any disc - except an L-format one - to get the values of bits 0 - 28 inclusive:

address = ((t × H + h) × S + s - x) × B + b

Tracks, heads and sectors are all counted from zero.

Bits 29 - 31 contain the drive number.

See also the Calculating disc addresses, which tells you how to calculate a physical disc address from the position of an allocation bit in a new map.

Internal disc addresses

Internal disc addresses are used by new map discs only. An object's internal disc address is in the following binary form:

ddd00000 0fffffff ffffffff ssssssss

ddd is the disc number (not useful outside FileCore)

fffffffffffffff is the fragment id

ssssssss is the sector offset within the object.

If the sector offset is 0, then the object does not share its disc object, and is located at the start of the disc object.

If the sector offset is non-zero (eg is s), then the object shares its disc object, and is located at the start of the sth sector of the disc object. So disc address:

0x00000233

means that this object (in fact the directory $) starts at the &33th sector in object 2. Note that the &33th sector starts &32 sectors into the disc object (ie the 1st sector is at the start of the object).

Directories

There are two types of directories used in RISC OS: the old directories used by L format, and the new directories used by later formats:

Directories

Size (entries)

Size (bytes)

Top bit set chars

Old

47

1280

No

New

77

2048

Yes

For both formats the directory is arranged as follows:

DirHeader

Entries[n]

where n = 47 or 77, as above

DirTail

The header and tail contain information about this directory, and the entries are the directory entries.

DirHeaders

The two directory formats have the same DirHeader:

Name

Bytes

Meaning

StartMasSeq

1

Update sequence number to check dir start with dir end

StartName

4

'Hugo' or 'Nick'

BBC and Master series computers always use 'Hugo' for L-format discs; for compatibility, we suggest you do the same. For other formats you can use either.

Entries

The two directory formats have mostly the same entry format:

Name

Bytes

Meaning

DirObName

10

Name of object

DirLoad

4

Load address of object

DirExec

4

Exec address of object

DirLen

4

Length of object

DirIndDiscAdd

3

Indirect disc address of object

OldDirObSeq or NewDirAtts

1

The NewDirAtts are as follows:

Bit

Meaning when set

0

Object has owner read access

1

Object has owner write access

2

Object is locked

3

Object is a directory

4

Object has public read access

5

Object has public write access

6

Reserved (must be zero)

7

Reserved (must be zero)

DirTails

The DirTail formats are, however, quite different:

Old DirTail

Name

Bytes

Meaning

OldDirLastMark

1

0 to indicate end of entries

OldDirName

10

Directory name

OldDirParent

3

Indirect disc address of parent directory

OldDirTitle

19

Directory title

Reserved

14

Reserved - must be zero

EndMasSeq

1

To match with StartMasSeq

EndName

4

'Hugo' or 'Nick', to match with StartName

DirCheckByte

1

Check byte on directory

New DirTail

Name

Bytes

Meaning

NewDirLastMark

1

0 to indicate end of entries

Reserved

2

Reserved - must be zero

NewDirParent

3

Indirect disc address of parent directory

NewDirTitle

19

Directory title

NewDirName

10

Directory name

EndMasSeq

1

To match with StartMasSeq

EndName

4

'Hugo' or 'Nick', to match with StartName

DirCheckByte

1

Check byte on directory

Notes

The last entry is indicated by there being a 0 in the first byte of the next entry's DirObName. The xxxDirLastMark entry is there so that when the directory is full, and hence the last entry is not followed by a null DirObName, it is still followed by a null byte to indicate the end of the directory.

DirObNames and DirNames are control character terminated, and may be the full length of the fields they occupy (in which case there is no terminator).

The indirect disc address of an object on an old map disc is the most significant 3 bytes of its physical disc address. The indirect disc address of an object on a new map disc is the least significant 3 bytes of its internal disc address. For an explanation, see the chapter entitled Disc addresses.

Calculating StartMasSeq and EndMasSeq

StartMasSeq and EndMasSeq are there to check whether the directory was completely written out when it was last written out. For an unbroken directory they are always equal, and are increased by one (wrapping at 255 back to 0) whenever the directory is updated. This means that if the writing of the directory was stopped halfway through then the start and end master sequence numbers will not be the same, and so the directory will then be identified as broken. Their values should equal each other, but, apart from that, they can be anything.

Calculating DirCheckByte

This is an accumulation of the used bytes in a directory. The used bytes are all the bytes excluding the hole between the last directory entry and the beginning of the structure at the tail of the directory. The generation of the check byte is best described as an algorithm:

Starting at 0 an accumulation process is performed on a number of values. Whatever the sort of the value (byte or word) it is accumulated in the same way. Assuming r0 is the accumulation register and r1 the value to accumulate this is the accumulation performed:

EOR r0, r1, r0, ROR #13

All the whole words at the start of the directory are accumulated. This will leave a number of bytes (0 to 3) in the last directory entry (or at the end of the start structure in a directory if it's empty).

The last few bytes at the start of the directory are accumulated individually.

The first few bytes at the beginning of the end structure of the directory are accumulated. This is done to leave only a whole number of words left in the directory to be accumulated.

The last whole words in the directory are accumulated, except the very last word which is excluded as it contains the check byte.

The accumulated word has its four bytes exclusive ORd (EOR) together. This value is the check byte.

Boot blocks

Hard discs contain a 512 byte boot block at disc address &C00, which contains important information. (On a disc with 256-byte sectors, such as ADFS uses, this corresponds to sectors 12 and 13 on the disc.) A boot block has the following format:

Note that in memory, this information would be stored in the order disc record, then defect list/hardware parameters. This is to facilitate passing the values to FileCore SWIs.

Defect list

A defect list is a list of words. Each word contains the disc address of the first byte of a sector which has a defect. This address is an absolute one, and does not take into account preceding defective sectors. The list is terminated by a word whose value is &200000xx. The byte xx is a check-byte calculated from the previous words. Assuming this word is initially set to &20000000, it can be correctly updated using this routine:

Hardware-dependent information

There is no guarantee how many bytes the hardware-dependent information may take up. As an example of use of this space, for the HD63463 controller the hardware parameters have the following contents:

Offset

Contents

&1B0 - &1B2

Unused

&1B3

Step pulse low

&1B4

Gap 2

&1B5

Gap 3

&1B6

Step pulse high

&1B7

Gap 1

&1B8 - &1B9

Low current cylinder

&1BA - &1BB

Pre-compensation cylinder

&1BC - &1BF

Unadjusted parking disc address

The boot block's disc record

The purpose of the boot block's disc record is to give the necessary information to find the disc's map. You should not rely on the information it contains for any other purpose, unless it is unavailable in the disc's map. Consequently:

For an old map disc, you should use the boot block's disc record to find the map. If information you require is held in the map, you must use that in preference to the boot block's disc record.

For a new map disc, you should use the boot block's disc record to find the map. Once you have found the map you should then always use its disc record, rather than the boot block's.

For the format of a disc record, see the chapter entitled Disc record.

The non-ADFS partition descriptor

These 3 bytes are used to describe any non-ADFS partition on the disc. Such a partition must come at the end of the disc, and is excluded from all descriptions of the ADFS partition. Currently it is only used to describe a RISC iX partition:

Offset

Contents

&1FC

format identifier and flags:

bits 0 - 3

partition format identifier (1 RISC iX)

bits 4 - 7

flags (reserved - must be zero)

&1FD

low byte of start cylinder

&1FE

high byte of start cylinder

You can calculate the disc address of the start of the non-ADFS partition as follows:

Data format

Files stored using FileCore are sequences of bytes which always begin at the start of a sector and extend for the number of sectors necessary to accommodate the data contained in the file. The last sector used to accommodate the file may have a number of unused bytes at the end of it. The last 'data' byte in the file is derived from the file length stored in the catalogue entry for the file, or if the file is open, from its extent.

Disc identifiers

Many of the commands described below allow discs to be specified. Generally, you can refer to a disc by its physical drive number (eg 0 for the built-in floppy), or by its name.

Drive numbers

FileCore supports 8 drives. Drive numbers 0 - 3 are 'floppy disc drives', and drive numbers 4 - 7 are 'hard disc drives'. You cannot implement a filing system under FileCore that has more than four drives of the same physical type.

Disc names

The disc name is set using *NameDisc (see *NameDisc). When you refer to a disc by name it will be used if it is in a drive. Otherwise a 'Disc not present' error will be given if the disc has been previously seen, or a 'Disc not known' error if the disc has not been seen.

Machine code programs can trap these errors before they are issued. This allows the user to be prompted to insert the disc into the drive. See OS_UpCall 1 and 2 for details.

In fact, disc names may be used in any pathname given to the system. When used in a pathname, the disc name (or number) must be prefixed by a colon. Examples of pathnames with disc specifiers are:

*Cat :MikeDisc.fonts
*Info :4.LIB*.*

Note that :drive really means :drive.$.

Disc names can have wildcards in them, so long as the name only matches one of the discs that FileCore knows about for the filing system. If more than one name matches FileCore will return an 'Ambiguous disc name' error.

You are very strongly recommended to use disc names rather than drive numbers when you write programs.

Changing discs

FileCore keeps track of eight disc names per filing system, on a first in, first out basis. When you eject a floppy disc from the drive, FileCore still 'knows' about it. This means that if there are any directories set on that disc (the current directory, user root directory, or library), they will still be associated with it. Thus any attempt to load or run a file will result in a 'Disc not present/known' error.

However, this means that you can replace the disc and still use it, as if it had never been ejected. The same applies to open files on the disc; they remain open and associated with that disc until they are closed.

You can cause the old directories to be overridden by *Mounting a new disc once it has been inserted. This resets the CSD and so on. Alternatively, if you unset the directories (using *NoDir, *NoLib and *NoURD), then FileCore will use certain defaults when operations on these are required.

If there is no current directory, FileCore will use $ on the default drive. This is the configured default, or the one set by the last *Drive command.

If there is no user root directory set, then references to that directory will use $ on the default drive.

If there is no library set, then FileCore will try &.Library, $.Library and then the current directory, in that order.

Use

When an image filing system receives this service call it should:

Check the sector size, sectors per track, density, heads and lowest numbered sector id on a track (held in the disc record - see the chapter entitled Disc record) to see whether these correspond to a format it understands. However, it should not do so if any of the sector size, sectors per track, density or heads are 0, since this means they were not supplied by FileCore_MiscOp 0 (see FileCore_MiscOp); this should only occur on hard discs.

If it does not recognise the sector scheme, it should pass on the service call, unclaimed.

If it does recognise the sector scheme, it should then update the disc record's values for the disc size, sequence sides, double step and heads so they correspond with the recognised format.

It should only adjust the heads field in line with the sequence sides value: when clearing the sequence sides bit from being set it should increment the heads field by one, and when setting the sequence sides bit from being clear it should decrement the heads field by one - but if the heads field was 0 it must remain so.

Check the sector contents to see whether these correspond to a format it understands. It should read the sectors using FileCore_DiscOp 9 (see FileCore_DiscOp) with:

the options bits in R1 set to 2_01x0 (1 second timeout; ignore escape; scatter list optional; no alternative defect list)

the pointer to an alternative disc record in R1 addressing the one supplied in the service call

the disc number within the disc address in R2 matching that given in the service call disc record's root directory address (which is set to byte 0 on the relevant disc).

If it does not recognise the sector contents, it should pass on the service
call, unclaimed, with, if necessary, the new value for R6 set up by FileCore_DiscOp 9.

If it does recognise the sector contents, it should then update the disc record's values for the disc cycle id and disc name, and claim the service call. The returned disc record will be used in further accesses, and so must have the heads and disc size correct. The disc cycle id should be one of:

an id stored on the disc which changes each time the disc is updated'

a value (eg CRC) calculated from a proportion of the disc which is likely to change when the disc is updated, such as the map.

The buffer pointed to by R2 should be filled in with a short description of the disc's format suitable for use in the Current format menu entry. You should ensure this does not overflow the length of the buffer (given in R3).

FileCore itself claims this service call to recognise those discs it knows about.

On exit

R1 preserved
R2 = disc address of next byte to be transferred
R3 = pointer to next buffer location to be transferred
R4 = number of bytes not transferred

Interrupts

Interrupt status is undefined
Fast interrupts are enabled

Processor mode

Processor is in SVC mode

Re-entrancy

Not defined

Use

This call performs various disc operations as specified by bits 0 - 3 of R1:

Value

Meaning

Uses

Updates

0

Verify

R2, R4

R2, R4

1

Read sectors

R2, R3, R4

R2, R3, R4

2

Write sectors

R2, R3, R4

R2, R3, R4

3

Floppy disc: read track

R2, R3

Hard disc: read Id

R2, R3

4

Write track

R2, R3

5

Seek (used only to park)

R2

6

Restore

R2

7

Floppy disc: step in †

8

Floppy disc: step out †

9

Read sectors via cache

R2, R3, R4, R6

R2, R3, R4, R6

15

Hard disc: specify

R2

† These reason codes are only valid with the 1772 disc controller. They are not supported on 710/711 based machines (such as the A5000) and should be avoided for future compatibility.

Option bits

The option bits have the following meanings:

Bit 4

This bit is set if an alternate defect list for a hard disc is to be used. This is assumed to be in RAM 64 bytes after the start of the disc record pointed to by bits 8 - 31 of R1 shifted left 6 bits (so they form bits 2 - 25 of the pointer).

This bit may only be set for old map discs.

Bit 5

If this bit is set, then the meaning of R3 is altered. It does not point to the area of RAM to or from which the disc data is to be transferred. Instead, it points to a word-aligned list of memory address/length pairs. All but the last of these lengths must be a multiple of the sector size. These word-pairs are used for the transfer until the total number of bytes given in R4 has been transferred.

On exit, R3 points to the first pair which wasn't fully used, and this pair is updated to reflect the new start address/bytes remaining, so that a subsequent call would continue from where this call has finished.

This bit may only be set for reason codes 0 - 2.

Bit 6

If this bit is set then escape conditions are ignored during the operation, otherwise they cause it to be aborted.

Bit 7

If this bit is set, then the usual timeout for floppy discs of 1 second is not used. Instead FileCore will wait (forever if necessary) for the drive to become ready.

Disc address

The disc address must be on a sector boundary for reason codes 0 - 2 and 9, and on a track boundary for other reason codes. Note that you must make allowances for any defects, as the disc address is not corrected for them.

For reason code 6 (restore), the disc address is only used for the drive number; the bottom 29 bits should be set to zero.

The specify disc command (reason code 15) sets up the defective sector list, hardware information and disc description from the disc record supplied. Note that in memory, this information must be stored in the order disc record, then defect list/hardware parameters.

Read Track/ID (reason code 3)

If the alternate defect list option bit (bit 4) is set in R1 on entry when reading a track/ID, then a whole track's worth of ID fields is read. This usage is not available under RISC OS 2.

The call reads 4 bytes of sector ID information into the buffer pointed to by R3 for every sector on the track. The order of data is:

Cylinder
Head
Sector number
Sector size (0= 128, 1= 256, etc)

The operation is terminated after 200mS (1 revolution).

The first sector ID transferred will normally be that following the index mark (it may be the second if there is abnormal interrupt latency from the index pulse interrupt). The first two ID's read may also be duplicated at the buffer end due to interrupt latency. Consequently the buffer should be at least 16 bytes longer than the maximum number of IDs expected (512 bytes at most).

The disc record provided is updated to return the actual number of sectors per track found (at offset 1). Note to use this option you must provide a valid defect list, which at a minimum is a word of &20000000 following on after the disc record.

Write Track (reason code 4)

If R3 (the buffer pointer) is non-zero on entry, this reason code is used to write a track. This usage is specific to the 1772 disc controller.

If R3 is zero on entry, this reason code is instead used to format a track; R4 then points to a disc format structure. This usage is available with all controllers, but is not available under RISC OS 2.

An error is generated if the specified format is not possible to generate, or if the track requested is outside the valid range. The tracks are numbered from 0 to (number of tracks) - 1. The mapping of the address is controlled by the disc structure record.

Read sectors via cache (reason code 9)

This reason code reads sectors via a cache held in the RMA. It is not available under RISC OS 2.

To start a sequence of these operations, set R6 (the cache handle) to zero on entry. Its value will be updated on exit, and subsequent calls should use this new value.

The only start-up option (passed in bits 25 - 31 of R3) currently supported is No directory state which is indicated by setting bit 30. All other bits representing start-up options must be clear.

If the filing system does not support background transfers of data, R5 must be zero.

The hard disc map sizes are given using 1 byte for each disc, with drive 4 in the low byte, and drive 7 in the high byte. The byte should contain map size/256 (ie 2 for the old map). This is just a good guess and should not involve starting up the drives to read from them. You might store this in the CMOS RAM.

You must store the FileCore instance private word returned by this SWI in your module workspace; it is your module's means of identifying itself to FileCore.

When your module calls the addresses returned in R1 - R3, it must be in SVC mode with R12 holding the value of R0 that this SWI returned. Interrupts need not be disabled. R0, R1, R3 - R11 and R13 will be preserved by FileCore over these calls.

FileCore_DescribeDisc(SWI &40545)

On entry

On exit

--

Interrupts

Interrupt status is undefined
Fast interrupts are enabled

Processor mode

Processor is in SVC mode

Re-entrancy

Not defined

Use

This call returns a disc record in the 64 byte block passed to it. The record describes the disc's shape and format. For a definition of the format of a disc record, see the chapter entitled Disc record.

On entry

On exit

R0 - R3 preserved

Interrupts

Interrupt status is undefined
Fast interrupts are enabled

Processor mode

Processor is in SVC mode

Re-entrancy

Not defined

Use

This call fills in the disc format structure pointed to by R0 with the 'perfect' parameters for the specified format, taking no account of the abilities of the available hardware that will have to perform the format. Once filled in, this SWI calls the vetting SWI to check the format structure for achievability on the available hardware. The vetting SWI may generate an error if the format differs widely from what can be achieved; alternatively it may alter the format structure to the closest match that can be achieved. The vetting SWI then returns to this SWI, which checks whether the format block - as updated by the vetting SWI - is still an adequate match for the desired format. If it is, this SWI returns to its caller; otherwise it generates an error.

The following format specifiers are recognised:

Value

Meaning

&80

L format floppy

&81

D format floppy

&82

E format floppy

&83

F format floppy

The returned disc format structure contains the following information:

Offset

Length

Meaning

0

4

Sector size in bytes (which will be a multiple of 128)

4

4

Gap1 side 0

8

4

Gap1 side 1

12

4

Gap3

16

1

Sectors per track

17

1

Density:

1

single density (125Kbps FM)

2

double density (250Kbps FM)

3

double+ density (300Kbps FM)

(ie higher rotation speed double density)

4

quad density (500Kbps FM)

8

octal density (1000Kbps FM)

18

1

Options:

bit 0

1

index mark required

bit 1

1

double step

bits 2-3

0

interleave sides

1

format side 1 only

2

format side 2 only

3

sequence sides

bits 4-7

reserved - must be 0

19

1

Start sector number on a track

20

1

Sector interleave

21

1

Side/side sector skew (signed)

22

1

Track/track sector skew (signed)

23

1

Sector fill value

24

4

Number of tracks to format (ie cylinders/drive: normally 80)

28

36

Reserved - must be zero

This structure tells you how to format a disc. Note that it differs from that used in FileCore_DiscOp to actually format a track (see Offset Length Meaning). The differences are because the DiscOp structure only specifies the format of a single track.

On entry

On exit

R0 - R3 preserved

Interrupts

Interrupt status is undefined
Fast interrupts are enabled

Processor mode

Processor is in SVC mode

Re-entrancy

Not defined

Use

This call lays out into the specified file a set of structures corresponding to the identified format. The format identifier is a pointer to a disc record. An error is returned if the specified format can not map out defects, and there were defects in the defect list.

On exit

R1 - R5 preserved

Use

This call mounts a disc, reading in the data asked for.

Floppy discs, and hard discs that may be mounted like floppies

For a floppy disc, and for hard discs where bit 4 of the descriptor block flags is set, this call asks the given filing system to first identify the disc's format. The suggested density to try first is given in the disc record; if this is not successful, the filing system should then try other densities. The following order is suggested:

Quad density

Double density

Octal density

Single density

Double+ density

Once the filing system has identified the disc's format, it fills in the log2secsize, secspertrack, heads, density, lowsector and root values in the disc record (see the chapter entitled Disc record).

If log2secsize 8, then it gives heads the value (actual number of heads-1), and sets bit 6 of lowsector, so sides are treated as sequenced. Otherwise (ie when log2secsize > 8) it gives heads the value (actual number of heads), and clears bit 6 of lowsector, so sides are treated as interleaved.

The filing system clears bit 7 of lowsector; this is used as an initial value, which FileCore subsequently corrects if necessary.

Having filled in the disc record, the filing system then reads in the data asked for.

Other hard discs

For hard discs where bit 4 of the descriptor block flags is clear (see the chapter entitled Descriptor block), this merely asks the given filing systems to read in the data asked for. This typically necessitates it reading the boot block off the disc; if the disc doesn't have one, the filing system generates one itself.

FileCore_MiscOp 1(SWI &40549)

Poll changed

On entry

On exit

R2 = sequence number
R3 = result flags

Use

The sequence number is to ensure no changes are lost due to reset being pressed. Both the given filing system and the FileCore incarnation should start with a sequence number of 0 for each drive. The filing system increments the sequence number with each change of state. If the filing system finds the entry sequence number does not match its copy it should return changed/maybe changed, depending on whether the disc changed line works/doesn't work.

The bits in the result flags have the following meanings:

Bit

Meaning when set

0

not changed

1

maybe changed

2

changed

3

empty

4

ready

5

drive is 40 track

6

empty works

7

changed works

8

disc in drive is high density

9

density sensing works

10

ready works

11 - 31

reserved - must be zero

Exactly one of bits 0 - 3 must be set. Once bit 6 or 7 is returned set for a given drive, they must always be so.

FileCore_MiscOp 2(SWI &40549)

Locks a disc in a floppy drive

On entry

On exit

--

Use

This call locks a disc in a drive; you can only use it for a floppy drive. It should at least ensure that the drive light stays on until unlocked. Note that locks are counted, so each 'Lock drive' must be matched by an 'Unlock drive'.

FileCore_MiscOp 3(SWI &40549)

Unlocks a disc in a floppy drive

On entry

R0 = 3
R1 = drive
R8 = pointer to FileCore instance private word

On exit

--

Use

This call can only be called for a floppy drive. It reverses a single 'Lock drive' MiscOp. Note that locks are counted, so 'Unlock drive' must be called for each 'Lock drive'.

FileCore_MiscOp 4(SWI &40549)

Informs FileCore of the minimum period between polling for disc insertion

On exit

Use

This call informs FileCore of the minimum period between polling for disc insertion under the given filing system. This is so that drive lights do not remain continuously illuminated.

The values are re-exported by FileCore in the UpCalls MediaNotPresent and MediaNotKnown. The value applies to all drives rather than a particular drive.

FileCore_MiscOp 5(SWI &40549)

Power-ejects the disc in the specified drive

On entry

R0 = 5
R1 = drive
R8 = pointer to FileCore instance private word

On exit

--

Use

This call power-ejects the disc in the specified drive, provided that the hardware is capable of it.

This reason code was introduced in RISC OS 3 (version 3.10).

* Commands

*Backup

Copies the used part of a floppy disc.

Syntax

*Backup source_drivedest_drive [Q]

Parameters

source_drive - the number of the source floppy drive (0 to 3)dest_drive - the number of the destination floppy drive (0 to 3)Q - speeds up the operation, by using the application work area as a buffer if extra room is needed to perform the backup, so fewer disc accesses are done. You must save any work you have done and quit any applications you are using before using this option.

Use

*Backup copies the used part of one floppy disc to another; free space is not copied. If the source drive is the same as the destination (as it is on a single floppy drive system), you will be prompted to swap the disc, as necessary.

The command only applies to floppy, not hard discs.

Example

*Backup 0 1

Related commands

*Copy

*Bye

Ends a filing system session.

Syntax

*Bye

Use

*Bye ends a filing system session by closing all files, unsetting all directories and libraries, forgetting all floppy disc names and parking the heads of hard discs to their 'transit position' so that the hard disc unit can be moved without risking damage to the read/write head.

You should check that the correct filing system is the current one before you use this command, or alternatively precede the command by the filing system name. For example you could end an ADFS session when another filing system is your current one by typing:

*adfs:Bye

Related commands

*Close, *Dismount, *Shut, *Shutdown

*CheckMap

Checks a disc map for consistency.

Syntax

*CheckMap [disc_spec]

Parameters

disc_spec - the name of the disc or number of the disc drive

Use

*CheckMap checks that the map of an E- or F-format disc (whether floppy or hard) has the correct checksums and is consistent with the directory tree. If only one copy of the map is good, it allows you to rewrite the bad one with the information in the good one.

In doing so, it closes all files on the disc.

Example

*CheckMap :Mydisc

Related commands

*Defect, *Verify

*Compact

Collects together free space on a disc

Syntax

*Compact [disc_spec]

Parameters

disc_spec - the name of the disc or number of the disc drive

Use

*Compact collects together free space on a disc by moving files. If no argument is given, the *Compact command is carried out on the current disc. *Compact works on either hard or floppy discs.

You cannot add a file to an old map disc (ie an L or D format disc, or an old map hard disc) that is larger than the biggest single free space. Because *Compact gathers together free space, the maximum size of file you can fit on the disc will be as high as is possible after you use this command.

The maximum size of file you can add to an E or F format disc does not depend on how fragmented the free space is, so there is not the same need to compact them. This command is still useful, as it will attempt to gather together any fragmented files, and generally tidy the disc up.

Example

*Compact :0

Related commands

*CheckMap, *FileInfo, *Map

*Configure Dir

Sets the configured disc mounting so that discs are mounted at power on

Syntax

*Configure Dir

Use

*Configure Dir sets the configured disc mounting so that, for each FileCore-based filing systems that support mounting:

a disc gets mounted at power on

the current directory is set to the root directory of the actual mounted disc (eg adfs::SystemDisc.$).

NoDir is the default setting.

This command is in fact provided by the kernel; however, since it is FileCore that looks at the configured value, it is included in this chapter for clarity.

Related commands

*Configure Drive, *Configure NoDir, *Mount

*Configure NoDir

Sets the configured disc mounting so that discs are not mounted at power on.

Syntax

*Configure NoDir

Use

*Configure NoDir sets the configured disc mounting so that for each FileCore-based filing system that supports mounting:

nothing gets mounted at power on.

the current directory is set to the root directory of the configured drive (eg adfs::0.$).

This is the default setting.

This command is in fact provided by the kernel; however, since it is FileCore that looks at the configured value, it is included in this chapter for clarity.

Related commands

*Configure NoDir, *Configure Drive, *Mount

*Dismount

Ensures that it is safe to finish using a disc

Syntax

*Dismount [disc_spec]

Parameters

disc_spec - the name of the disc or number of the disc drive

Use

*Dismount ensures that it is safe to finish using a disc by closing all its files, unsetting all its directories and libraries, forgetting its disc name (if a floppy disc) and parking its read/write head. If no disc is specified, the current disc is used as the default. *Dismount is useful before removing a particular floppy disc, and is essential if the disc is to taken away and modified on another computer. However, the *Shutdown command is usually to be preferred, especially when switching off the computer.

Example

*Dismount

Related commands

*Mount, *Shutdown

*Drive

Sets the current drive

Syntax

*Drive drive

Parameters

drive - the number of the disc drive, from 0 to 7

Use

*Drive sets the current drive if NoDir is set. Otherwise, *Drive has no meaning. The command is provided for compatibility with early versions of ADFS.

Example

*Drive 3

Related commands

*Dir, *NoDir

*Free

Displays the total free space remaining on a disc

Syntax

*Free [disc_spec]

Parameters

disc_spec - the name of the disc or number of the disc drive

Use

*Free displays the total free space remaining on a disc. If no disc is specified, the total free space on the current disc is displayed.

Related commands

*Map

Syntax

Parameters

Use

*Map displays a disc's free space map. If no disc is specified, the map of the current disc is displayed.

Example

*Map :Mydisc

Related commands

*Compact, *Free

*Mount

Prepares a disc for general use

Syntax

*Mount [disc_spec]

Parameters

disc_spec - the name of the disc or number of the disc drive

Use

*Mount prepares a disc for general use by setting the current directory to its root directory, setting the library directory (if it is currently unset) to $.Library, and unsetting the User Root Directory (URD). If no disc spec is given, the default drive is used. The command is preserved for the sake of compatibility with earlier Acorn operating systems, and ideally you should not use it.

Example

*Mount :mydisc

Related commands

*Dismount

*NameDisc

Changes a disc's name

Syntax

*NameDisc disc_specnew_name

Parameters

disc_spec - the present name of the disc or number of the disc drivenew_name - the new name of the disc, which may be up to 10 characters long

Use

*NameDisc (or alternatively, *NameDisk) changes a disc's name.

Example

*NameDisc :0 DataDisc

Related commands

None

*Title

Sets the title of the current directory

Syntax

*Title [text]

Parameters

text - a text string of up to 19 characters

Use

*Title sets the title of the current directory. Titles take no place in pathnames, and should not be confused with disc names. Spaces are permitted in *Title names.

Titles are output by some * Commands that print headers before the rest of the information they provide: for example *Ex.

This command is not available after RISC OS 2, and you should no longer use it.

Related commands

*Cat, *Ex

*Verify

Checks a disc for readability

Syntax

*Verify [disc_spec]

Parameters

disc_spec - the name of the disc or number of the disc drive

Use

*Verify checks that the whole disc is readable, except for sectors that are already known to be defective. The default is the current disc.

Use *Verify to check discs which give errors during writing or reading operations. It can check both floppy discs and hard discs.

*Verify uses a hard disc controller 'primitive' routine which does not attempt retries if a read error occurs. Occasional misreads are not abnormal in hard disc systems, and in normal operation FileCore corrects these by retrying. *Verify may therefore occasionally indicate an error which under normal use would not be encountered. Only if an error is reported consistently at the same sector address should further action be taken.