RISCOS.com

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.

See also the Introduction to filing systems.

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.

For full details, see the chapter entitled Writing a FileCore module.

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.)

and for hard discs:

    Format Map Zones Directories Boot block
    D Old -- New Yes
    E New >=1 New Yes

For details of the various terms used above see the chapters entitled Old maps, New maps, Directories, and Boot blocks.

Physical layout

This table shows the physical layout of 'perfect' ADFS formats:

    Format Density Sectors/track Bytes/sector Storage Heads
    L Double 16 256 640K 1
    D Double 5 1024 800K 2
    E Double 5 1024 800K 2
    F Quad 10 1024 1.6M 2
    Hard -- -- -- <=512M --

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 mechanical index pulse and the magnetic index 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:

ADC  r0, r0, r1         r1 is the byte picked up
MOVS r0, r0, LSL #24    Shifts bit 8 into the carry bit
MOV  r0, r0, LSR #24    Not MOVS here to preserve the carry bit

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.

The general format of a map block is as follows:

Header
Disc record (Zone 0 only)
Allocation bytes
Unused

Header

A map block header is as follows:

Offset Name Meaning
0 ZoneCheck Check byte for this zone's map block
1 FreeLink Link to first free fragment in this zone
3 CrossCheck Cross check byte for complete map

ZoneCheck is used to check that this zone's map block is valid; see the chapter entitled Calculating ZoneCheck....

FreeLink is a fragment block giving the offset to the first free space fragment block in the allocation bytes; see later (fragment Ids)..

CrossChecks are combined to check that the whole map is self-consistent; see the chapter entitled Calculating CrossCheck.

Disc record

The format of a disc record is as follows:

Offset Name Meaning
0 log2secsize Log2 (sector size of disc in bytes)
1 secspertrack Number of sectors per track
2 heads Number of disc heads if sides interleaved
Number of disc heads - 1 if sides sequenced
(1 for old directories)
3 density
0 hard disc
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)
4 idlen Length of id field of a map fragment, in bits
5 log2bpmb Log2 (number of bytes per map bit)
6 skew Track to track sector skew for random access file allocation
7 bootoption Boot option (as in *Opt 4,n)
8 lowsector
bits 0 - 5: lowest numbered sector id on a track
bit 6: if set, treat sides as sequenced (rather than interleaved)
bit 7: if set, disc is 40 track
9 nzones Number of zones in the map
10 zone_spare Number of non-allocation bits between zones
12 root Disc address of root directory
16 disc_size Disc size, in bytes
20 disc_id Disc cycle id
22 disc_name Disc name
32 disctype File type given to disc
36 - 59 Reserved - must be zero

Bytes 4 - 11 inclusive must be zero for old map discs.

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.

Other fragment ids represent either free space fragments, or allocated fragments:

  • 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:

    allocation bytes × 8 / (idlen + 1) - ie allocation bits / minimum fragment size

    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:

...using C

unsigned char map_zone_valid_byte
(
    void const * const map,
    disc_record const * const discrec,
    unsigned int zone
)
{
    unsigned char const * const map_base = map;
    unsigned int sum_vector0;
    unsigned int sum_vector1;
    unsigned int sum_vector2;
    unsigned int sum_vector3;
    unsigned int zone_start;
    unsigned int rover;
    sum_vector0 = 0;
    sum_vector1 = 0;
    sum_vector2 = 0;
    sum_vector3 = 0;
    zone_start = zone<<discrec->log2_sector_size;
    for ( rover = ((zone+1)<<discrec->log2_sector_size)-4 ;
          rover > zone_start;
          rover-=4 )
{
        sum_vector0 += map_base[rover+0] + (sum_vector3>>8);
        sum_vector3 &= 0xff;
        sum_vector1 += map_base[rover+1] + (sum_vector0>>8);
        sum_vector0 &= 0xff;
        sum_vector2 += map_base[rover+2] + (sum_vector1>>8);
        sum_vector1 &= 0xff;
        sum_vector3 += map_base[rover+3] + (sum_vector2>>8);
        sum_vector2 &= 0xff;
}
/*
    Don't add the check byte when calculating its value
*/
    sum_vector0 += (sum_vector3>>8);
    sum_vector1 += map_base[rover+1] + (sum_vector0>>8);
    sum_vector2 += map_base[rover+2] + (sum_vector1>>8);
    sum_vector3 += map_base[rover+3] + (sum_vector2>>8);
    return (unsigned char)
            ((sum_vector0^sum_vector1^sum_vector2^sum_vector3)
            & 0xff);
}

...using assembler

; ========
; NewCheck
; ========
;entry
; R0 -> start
; R1 length ( must be multiple of 32 )
;exit
; LR check byte, Z=0 <=> good
NewCheck ROUT
 Push "R1-R9,LR"
 MOV LR, #0
 ADDS R1, R1, R0   ;C=0
05                 ;loop optimised as winnies may have many zones
 LDMDB R1!,{R2-R9}
 ADCS LR, LR, R9
 ADCS LR, LR, R8
 ADCS LR, LR, R7
 ADCS LR, LR, R6
 ADCS LR, LR, R5
 ADCS LR, LR, R4
 ADCS LR, LR, R3
 ADCS LR, LR, R2
 TEQS R1, R0       ;preserves C
 BNE  %BT05
 AND  R2, R2, #&FF ;ignore old sum
 SUB  LR, LR, R2
 EOR  LR, LR, LR, LSR #16
 EOR  LR, LR, LR, LSR #8
 AND  LR, LR, #&FF
 CMPS R2, LR
 Pull "R1-R9,PC"

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:

Offset Contents
&000 upwards Defect list
&1BF downwards Hardware-dependent information
&1C0 - &1FB Disc record (see Disc record)
&1FC - &1FE Non-ADFS partition descriptor
&1FF Check sum byte

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:

On entry

Ra = pointer to start of defect list

On exit

Ra corrupt
Rb = check byte
Rc corrupt

        MOV     Rb,#0                   ; init check
loop
        LDR     Rc,[Ra],#4              ; get next entry
        CMPS    Rc,#&20000000           ;all done ?
        EORCC   Rb,Rc,Rb,ROR #13
        BCC     loop
        EOR     Rb,Rb,Rb,LSR #16        ; compress word to byte
        EOR     Rb,Rb,Rb,LSR #8
        AND     Rb,Rb,#&FF

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:

start cylinder × heads on drive × sectors per track × bytes per sector

Calculating the boot block's checksum byte

The last byte of the boot block is a checksum byte whose value is calculated as follows:

  • Perform an 8 bit add with carry on each of the other bytes in the block, starting with value 0.

In assembler this might be done as follows:

; entry: R0=start, R1=block length
; exit: R0,R1 preserved, R2=checksum
CheckSum ROUT
        STMFD    R13!, {R1, LR}
        ADDS     LR, R0, R1         ;->end+1 C=0
        SUB      R1, LR, #1         ;->check byte
        MOV      R2, #0
        B        %FT20
10
        LDRB     LR, [R1,#-1] !     ;get next byte
        ADC      R2, R2, LR         ;add into checksum
        MOVS     R2, R2, LSL #24    ;bit 8 = carry
        MOV      R2, R2, LSR #24
20
        TEQS     R0, R1
        BNE      %BT10              ;loop until done
        LDMFD    R13!, {R1, LR}

Note that the checksum doesn't include the last byte.

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.

See also Service_DiscDismounted (Service Call &7D).

Current selections

The currently selected directory, user root directory and library directory are all stored independently for each FileCore-based filing system.

Service Calls


Service_IdentifyDisc
(Service Call &69)

Identify disc format

On entry

R1 = &69 (reason code)
R2 = pointer to buffer
R3 = length of buffer
R5 = pointer to disc record
R6 = sector cache handle
R8 = pointer to FileCore instance private word to use

On exit

If the format has been identified:

R1 = 0 to claim call
R2 = filetype number for given disc format.
R5 = pointer to disc record, which has been modified
R6 = new sector cache handle
R8 preserved

Otherwise:

R1, R5 preserved
R6 = new sector cache handle
R8 preserved

Use

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

  1. 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.
  2. If it does not recognise the sector scheme, it should pass on the service call, unclaimed.
  3. 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.

  4. 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).
  5. 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.
  6. 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.

In summary:
  • Check sector size, sectors per track, density, heads and low sector
  • Pass on service call if no match
  • Update disc size and heads fields and sequence sides and double step bits
  • Check sector contents
  • Pass on service call if no match
  • Update disc cycle id and disc name
  • Fill in buffer with description for Current format menu entry
  • Claim service.

SWI Calls


FileCore_DiscOp
(SWI &40540)

Performs various operations on a disc

On entry

R1 = reason code and options

bits 0 - 3 = reason code
bits 4 - 7 = option bits
bits 8 - 31 = bits 2 - 25 of pointer to alternative disc record, or zero
R2 = disc address
R3 = pointer to buffer
R4 = length in bytes
R6 = cache handle
R8 = pointer to FileCore instance private word

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.

The disc format structure pointed to by R4 is as follows:

Offset Length Meaning
0 4 Sector size in bytes (which must be a multiple of 128)
4 4 Gap1
8 4 Reserved - must be zero
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 - 3 sequence sides
bits 4-7 reserved - must be 0
19 1 Sector fill value
20 4 Cylinders per drive (normally 80)
24 12 Reserved - must be 0
36 ? Sector ID buffer, 1 word per sector:
bits 0 - 7 Cylinder number mod 256
bits 8 - 15 Head (0 for side 1, 1 for side 2)
bits 16 - 23 Sector number
bits 24 - 31 Log2 (sector size) - 7, eg 1 for 256 byte sector

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.

Bits 4 - 7 of R1 should be zero, and are ignored if set.

To discard the cache once finished, call FileCore_DiscardReadSectorsCache (see FileCore_DiscardReadSectorsCache).

Related SWIs

None

Related vectors

None


FileCore_Create
(SWI &40541)

Creates a new instantiation of an ADFS-like filing system

On entry

R0 = pointer to descriptor block
R1 = pointer to calling module's base
R2 = pointer to calling module's private word
R3

bits 0 - 7 = number of floppies
bits 8 - 15 = number of hard discs
bits 16 - 24 = default drive
bits 25 - 31 = start up options
R4 = suggested size for directory cache
R5 = suggested number of 1072 byte buffers for file cache
R6 = hard disc map sizes

On exit

R0 = pointer to FileCore instance private word
R1 = address to call after completing background floppy op
R2 = address to call after completing background hard disc op
R3 = address to call to release FIQ after low level op

Interrupts

Interrupt status is undefined
Fast interrupts are enabled

Processor mode

Processor is in SVC mode

Re-entrancy

Not defined

Use

This call creates a new instantiation of an ADFS-like filing system. It must be called on initialisation by any filing system module that is adding itself to FileCore.

The descriptor block is described in the Writing a FileCore module.

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.

Related SWIs

None

Related vectors

None


FileCore_Drives
(SWI &40542)

Returns information on the filing system's drives

On entry

R8 = pointer to FileCore instance private word

On exit

R0 = default drive
R1 = number of floppy drives
R2 = number of hard disc drives

Interrupts

Interrupt status is undefined
Fast interrupts are enabled

Processor mode

Processor is in SVC mode

Re-entrancy

Not defined

Use

This call returns information on the filing system's drives.

Related SWIs

None

Related vectors

None


FileCore_FreeSpace
(SWI &40543)

Returns information on a disc's free space

On entry

R0 = pointer to disc specifier (null terminated)
R8 = pointer to FileCore instance private word

On exit

R0 = total free space on disc
R1 = size of largest object that can be created

Interrupts

Interrupt status is undefined
Fast interrupts are enabled

Processor mode

Processor is in SVC mode

Re-entrancy

Not defined

Use

This call returns the total free space on the given disc, and the largest object that can be created on it.

Related SWIs

None

Related vectors

None


FileCore_FloppyStructure
(SWI &40544)

Creates a RAM image of a floppy disc map and root directory entry

On entry

R0 = pointer to buffer (must be >= 4K long)
R1 = pointer to disc record describing shape and format
R2

bit 7 set for old directory structure
bit 6 set for old map
R3 = pointer to list of defects

On exit

R3 = total size of structure created

Interrupts

Interrupt status is undefined
Fast interrupts are enabled

Processor mode

Processor is in SVC mode

Re-entrancy

Not defined

Use

This call creates a RAM image of a floppy disc map and root directory entry.

The pointer to a list of defects is only needed for new map discs. They must be byte addresses giving the start of defective sectors, and terminated with &20000000.

You do not need to know a FileCore instantiation private word to use this call; instead the disc record tells FileCore which filing system is involved.

Related SWIs

None

Related vectors

None


FileCore_DescribeDisc
(SWI &40545)

Returns a disc record describing a disc's shape and format

On entry

R0 = pointer to disc specifier (null terminated)
R1 = pointer to 64 byte block
R8 = pointer to FileCore instance private word

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.

Related SWIs

None

Related vectors

None


FileCore_DiscardReadSectorsCache
(SWI &40546)

Discards the cache of read sectors created by FileCore_DiscOp 9

On entry

R6 = Cache handle

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 discards the cache of read sectors created by FileCore_DiscOp 9 (see Read sectors via cache (reason code 9)).

This call is not available under RISC OS 2.

Related SWIs

None

Related vectors

None


FileCore_DiscFormat
(SWI &40547)

Fills in a disc format structure with parameters for the specified format

On entry

R0 = pointer to disc format structure to be filled in
R1 = SWI number to call to vet disc format (eg ADFS_VetFormat)
R2 = parameter in R1 to use when calling vetting SWI
R3 = format specifier

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.

This call is not available under RISC OS 2.

Related SWIs

ADFS_VetFormat, DOSFS_DiscFormat

Related vectors

None


FileCore_LayoutStructure
(SWI &40548)

Lays out into the specified file a set of structures for its format

On entry

R0 = identifier of particular format to lay out
R1 = pointer to bad block list (terminated by -1)
R2 = pointer to null-terminated disc name
R3 = image file handle

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.

This call is not available under RISC OS 2.

Related SWIs

None

Related vectors

None


FileCore_MiscOp
(SWI &40549)

Perform miscellaneous functions for accessing drives

On entry

R0 = reason code
R1 = drive
R2 - R5 depend on reason code
R8 = pointer to FileCore instance private word

On exit

R0 - R6 depend on reason code

Interrupts

Interrupt status is undefined
Fast interrupts are enabled

Processor mode

Processor is in SVC mode

Re-entrancy

Not defined

Use

This call performs miscellaneous functions for accessing drives, depending on the reason code in R0. Valid reason codes are:

Value Meaning Page
0 Mount FileCore_MiscOp 0
1 Poll changed FileCore_MiscOp 1
2 Lock drive FileCore_MiscOp 2
3 Unlock drive FileCore_MiscOp 3
4 Poll period FileCore_MiscOp 4
5 Eject disc FileCore_MiscOp 5)

This call is not available under RISC OS 2.

Related SWIs

None

Related vectors

None


FileCore_MiscOp 0
(SWI &40549)

Mounts a disc, reading in the data asked for

On entry

R0 = 0
R1 = drive
R2 = disc address to read from
R3 = pointer to buffer
R4 = length to read into buffer
R5 = pointer to disc record to fill in (floppies and floppy-like hard discs only)
R8 = pointer to FileCore instance private word

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:

  1. Quad density
  2. Double density
  3. Octal density
  4. Single density
  5. 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

R0 = 1
R1 = drive
R2 = sequence number
R8 = pointer to FileCore instance private word

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

R0 = 2
R1 = floppy drive
R8 = pointer to FileCore instance private word

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 entry

R0 = 4
R1 = pointer to disc name (may not be terminated if maximum length)
R8 = pointer to FileCore instance private word

On exit

R5 = minimum polling period (in centiseconds), or -1 if disc changed doesn't work
R6 = pointer to media type string: eg 'disc' for ADFS

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_drive dest_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.

Example

*Free 4
Bytes free &2F36C800 =   792,119,296
Bytes used &0392D800 =    59,955,200

Related commands

*Map


*Map

Displays a disc's free space map

Syntax

*Map [disc_spec]

Parameters

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

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_spec new_name

Parameters

disc_spec - the present name of the disc or number of the disc drive
new_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.

Example

*Verify 4

*Verify :Mydisc

Related commands

*Defect

This edition Copyright © 3QD Developments Ltd 2015
Last Edit: Tue,03 Nov 2015