www.riscos.com Technical Support: |
|
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.
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.
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:
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.
When you add a new module to FileCore, there is comparatively little work to be done. It needs:
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.
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.
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.
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:
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:
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 |
A sector is laid out as follows:
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.
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:
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.
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.
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
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.
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 |
| ||||||||||||
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 |
| ||||||||||||
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.
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:
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:
Other fragment ids represent either free space fragments, or allocated fragments:
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.
The following deductions can be made:
(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).
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.
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)
(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.
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.
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.
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).
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:
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); }
; ======== ; 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"
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.
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.
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:
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 are used by new map discs only. An object's internal disc address is in the following binary form:
ddd00000 0fffffff ffffffff ssssssss
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).
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.
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.
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) |
The DirTail formats are, however, quite different:
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 |
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 |
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.
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.
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.
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.
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:
Ra = pointer to start of defect list
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
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 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.
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
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}
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.
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.
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.
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.
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.
The currently selected directory, user root directory and library directory are all stored independently for each FileCore-based filing system.
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
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
When an image filing system receives this service call it should:
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.
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.
R1 = reason code and options
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
Interrupt status is undefined
Fast interrupts are enabled
Processor is in SVC mode
Not defined
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.
The option bits have the following meanings:
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 5If 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 6If this bit is set then escape conditions are ignored during the operation, otherwise they cause it to be aborted.
Bit 7If 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.
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.
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.
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:
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.
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).
None
R0 = pointer to descriptor block
R1 = pointer to calling module's base
R2 = pointer to calling module's private word
R3
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
Interrupt status is undefined
Fast interrupts are enabled
Processor is in SVC mode
Not defined
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.
None
R8 = pointer to FileCore instance private word
R0 = default drive
R1 = number of floppy drives
R2 = number of hard disc drives
Interrupt status is undefined
Fast interrupts are enabled
Processor is in SVC mode
Not defined
This call returns information on the filing system's drives.
None
None
R0 = pointer to disc specifier (null terminated)
R8 = pointer to FileCore instance private word
R0 = total free space on disc
R1 = size of largest object that can be created
Interrupt status is undefined
Fast interrupts are enabled
Processor is in SVC mode
Not defined
This call returns the total free space on the given disc, and the largest object that can be created on it.
None
None
Creates a RAM image of a floppy disc map and root directory entry
R0 = pointer to buffer (must be 4K long)
R1 = pointer to disc record describing shape and format
R2
R3 = total size of structure created
Interrupt status is undefined
Fast interrupts are enabled
Processor is in SVC mode
Not defined
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.
None
None
R0 = pointer to disc specifier (null terminated)
R1 = pointer to 64 byte block
R8 = pointer to FileCore instance private word
--
Interrupt status is undefined
Fast interrupts are enabled
Processor is in SVC mode
Not defined
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.
None
None
Discards the cache of read sectors created by FileCore_DiscOp 9
R6 = Cache handle
--
Interrupt status is undefined
Fast interrupts are enabled
Processor is in SVC mode
Not defined
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.
None
None
Fills in a disc format structure with parameters for the specified format
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
R0 - R3 preserved
Interrupt status is undefined
Fast interrupts are enabled
Processor is in SVC mode
Not defined
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.
Lays out into the specified file a set of structures for its format
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
R0 - R3 preserved
Interrupt status is undefined
Fast interrupts are enabled
Processor is in SVC mode
Not defined
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.
None
None
Perform miscellaneous functions for accessing drives
R0 = reason code
R1 = drive
R2 - R5 depend on reason code
R8 = pointer to FileCore instance private word
R0 - R6 depend on reason code
Interrupt status is undefined
Fast interrupts are enabled
Processor is in SVC mode
Not defined
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.
None
None
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
R1 - R5 preserved
This call mounts a disc, reading in the data asked for.
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:
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).
Having filled in the disc record, the filing system then reads in the data asked for.
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.
R0 = 1
R1 = drive
R2 = sequence number
R8 = pointer to FileCore instance private word
R2 = sequence number
R3 = result flags
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.
R0 = 2
R1 = floppy drive
R8 = pointer to FileCore instance private word
--
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'.
R0 = 3
R1 = drive
R8 = pointer to FileCore instance private word
--
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'.
Informs FileCore of the minimum period between polling for disc insertion
R0 = 4
R1 = pointer to disc name (may not be terminated if maximum length)
R8 = pointer to FileCore instance private word
R5 = minimum polling period (in centiseconds), or -1 if disc changed doesn't work
R6 = pointer to media type string: eg 'disc' for ADFS
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.
R0 = 5
R1 = drive
R8 = pointer to FileCore instance private word
--
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).
*Backup source_drive dest_drive [Q]
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.
*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.
*Backup 0 1
*Copy
Ends a filing system session.
*Bye
*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
*Close, *Dismount, *Shut, *Shutdown
*CheckMap [disc_spec]
disc_spec - the name of the disc or number of the disc drive
*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.
*CheckMap :Mydisc
*Defect, *Verify
*Compact [disc_spec]
disc_spec - the name of the disc or number of the disc drive
*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.
*Compact :0
*CheckMap, *FileInfo, *Map
Sets the configured disc mounting so that discs are mounted at power on
*Configure Dir
*Configure Dir sets the configured disc mounting so that, for each FileCore-based filing systems that support mounting:
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.
*Configure Drive, *Configure NoDir, *Mount
Sets the configured disc mounting so that discs are not mounted at power on.
*Configure NoDir
*Configure NoDir sets the configured disc mounting so that for each FileCore-based filing system that supports mounting:
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.
*Configure NoDir, *Configure Drive, *Mount
*Dismount [disc_spec]
disc_spec - the name of the disc or number of the disc drive
*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.
*Dismount
*Mount, *Shutdown
*Drive drive
drive - the number of the disc drive, from 0 to 7
*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.
*Drive 3
*Dir, *NoDir
*Free [disc_spec]
disc_spec - the name of the disc or number of the disc drive
*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.
*Free 4 Bytes free &2F36C800 = 792,119,296 Bytes used &0392D800 = 59,955,200
*Map
*Map [disc_spec]
disc_spec - the name of the disc or number of the disc drive
*Map displays a disc's free space map. If no disc is specified, the map of the current disc is displayed.
*Map :Mydisc
*Compact, *Free
*Mount [disc_spec]
disc_spec - the name of the disc or number of the disc drive
*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.
*Mount :mydisc
*Dismount
*NameDisc disc_spec new_name
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
*NameDisc (or alternatively, *NameDisk) changes a disc's name.
*NameDisc :0 DataDisc
None
*Title [text]
text - a text string of up to 19 characters
*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.
*Cat, *Ex
*Verify [disc_spec]
disc_spec - the name of the disc or number of the disc drive
*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.
*Verify 4
*Verify :Mydisc