; Copyright 1996 Acorn Computers Ltd
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
;     http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;
; >Identify

        TTL     "Identifying FileCore discs"

; change log:

; 15 May 1997: SBP: Changed SanityCheckEDiscRecord to support LinkBits up to 16.


; ============
; IdentifyDisc (r0,r5->r0,r6)
; ============
;
; Attempt to identify the specified disc
;
;entry
;  r0 = drive number of drive which disc to be identified is in
;  r5 -> disc record of disc to be identified
;
; exit
;  r0 = FileType of disc image (FileType_Data if service call failed)
;  r6 = readsectors cache
;  V not possible
;
IdentifyDisc ROUT
        Push    "r1,r2,r3,r8,r9,lr"

 [ DebugL
        DREG    R0, "Identifying drive ",cc
        DREG    R5, " on record at "
 ]

        ; Ensure an empty read sectors cache
        MOV     r6, #0

        ; If LastDiscOpWasFormat then disc must be a data disc
        DrvRecPtr lr, r0
        LDRB    lr, [lr, #DrvFlags]
        TST     lr, #LastDiscOpWasFormat
        MOVNE   r1, #Service_IdentifyDisc
        BNE     %FT50

	LDR	r9, [r5, #RootDir]
	AND	r9, r9, #DiscBits

 [ DebugL
	DREG	r9, "Rootdir internally starts as: "
 ]

        ; Generate an initial root dir address
        MOV     r1, r0, ASL #(32-3)
        EOR     r1, r1, #bit31          ; Convert to external numbering
 [ DebugL
	DREG	r1, "Setting initial root dir address to: "
 ]
        STR     r1, [r5, #RootDir]

        MOV     r1, #Service_IdentifyDisc
        MOV     r2, #0                  ; buffer
        MOV     r3, #0                  ; buffer size
        LDR     r8, PrivateWord

        BL      DoXOS_ServiceCall

        ; Fake unserviced service on VS result
        MOVVS   r1, #Service_IdentifyDisc
        CLRV

	LDR	lr, [r5, #RootDir]
	BIC	lr, lr, #DiscBits
	ORR	lr, lr, r9
	STR	lr, [r5, #RootDir]

 [ DebugL
	DREG	lr, "Restoring internal disc numbering of RootDir: "
 ]

50
        ; If not serviced then disc is just so much random data!
        TEQ     r1, #Service_Serviced
        ; Clear out DiscId and DiscName if mapping to FileType_Data
        MOVNE   r0, #0
        ASSERT  DiscId :MOD: 4 = 0
        ASSERT  DiscName = DiscId+2
        STRNE   r0, [r5, #DiscId]
        LDRNE   r0, =FileType_Data
        MOVEQ   r0, r2

 [ DebugL
        DREG    R0, "Disc identified as type "
 ]

95
        Pull    "r1,r2,r3,r8,r9,pc"

        LTORG

; ====================
; IdentifyFileCoreDisc
; ====================
;
;entry
;  R1 = Service_IdentifyDisc (&69)
;  r2 = pointer to buffer for text
;  r3 = length of buffer
;  R5 = Pointer to disc record
;  R6 = Sector cache handle
;  R8 = Pointer to FileCore instance private word to use
;
;exit
;If the format has been identified:
;  R1 = Service_Serviced
;  R2 = Filetype number for given disc format.
;  R5 = Pointer to disc record, which has been modified
;  R6 = New sector cache handle
;  R8 unchanged
;Otherwise:
;  R1 = Service_IdentifyDisc
;  R5 = Pointer to disc record, which may have been modified
;  R6 = New sector cache handle
;  R8 unchanged

IdentifyFileCoreDisc ROUT
        Push    "lr"
 [ DebugL
        DLINE   "Identifying a disc"
        DREG    R0, "Rin:",cc
        DREG    R1, ",",cc
        DREG    R2, ",",cc
        DREG    R3, ",",cc
        DREG    R4, ",",cc
        DREG    R5, ",",cc
        DREG    R6, ",",cc
        DREG    R7, ",",cc
        DREG    R8, ",",cc
        DREG    R9, ",",cc
        DREG    R10, ",",cc
        DREG    R11, ",",cc
        MOV     R12, R13
        DREG    R12, ","
 ]
       MOV     r12, r8
 [ DebugL
        DREG    r8, "r8 in is "
        DREG    r12, "Meaning ws is "
        Push    "r0"
        LDRB    r0, ReEntrance
        DREG    r0, "ReEntrance into service call servicing:"
        Pull    "r0"
 ]
        BL      IdentifyFileCoreFloppyDisc
        TEQ     r1, #Service_Serviced
        BLNE    IdentifyFileCoreHardDisc
 [ DebugL
        Push    "r0"
        LDRB    r0, ReEntrance
        DREG    r0, "ReEntrance out of service call servicing:"
        Pull    "r0"
        TEQ     r1, #Service_Serviced
        BNE     %FT01
        DREG    r2, "Service claimed - disc type is "
01
        DREG    R0, "Rot:",cc
        DREG    R1, ",",cc
        DREG    R2, ",",cc
        DREG    R3, ",",cc
        DREG    R4, ",",cc
        DREG    R5, ",",cc
        DREG    R6, ",",cc
        DREG    R7, ",",cc
        DREG    R8, ",",cc
        DREG    R9, ",",cc
        DREG    R10, ",",cc
        DREG    R11, ",",cc
        MOV     R12,R13
        DREG    R12, ","
 ]
        Pull    "pc"

        LTORG

; ==========================
; IdentifyFileCoreFloppyDisc
; ==========================
;entry
;  r1 = Service_IdentifyDisc (&69)
;  r5 = Pointer to disc record
;  r6 = Sector cache handle
;  r8 = Pointer to FileCore instance private word to use
;  r12 = Pointer to FileCore instance private word to use
;
;exit
;If the format has been identified:
;  r1 = Service_Serviced
;  r2 = Filetype number for given disc format.
;  r5 = Pointer to disc record, which has been modified
;  r6 = New sector cache handle
;  r8 unchanged
;  r12 unchanged
;Otherwise:
;  r1 = Service_IdentifyDisc
;  r5 = Pointer to disc record, which may have been modified
;  r6 = New sector cache handle
;  r8 unchanged
;  r12 unchanged

IdentifyFileCoreFloppyDisc ROUT
        Push    "r0,r1,r2,r3,r8,r12,lr"

 [ DebugL
        DLINE   "Identifying a floppy disc"
 ]

        ; Don't even try to identify hard discs as floppy discs.
        LDR     lr, [r5, #RootDir]
        TST     lr, #bit31
        BNE     %FT95

        ; Sector numbers must start at 0 on a track
        LDRB    r0, [r5, #LowSector]
        AND     lr, r0, #LowSectorMask
        TEQ     lr, #0
 [ DebugL
        BEQ     %FT01
        DLINE   "Failed on sector numbering"
01
 ]
        BNE     %FT95

        ; Must be two heads in reality, and turn off side sequencing and double stepping
        LDRB    r0, [r5, #LowSector]
        BIC     r0, r0, #DoubleStep
        STRB    r0, [r5, #LowSector]
        BL      EnsureInterleavedSides

        ; Ensure 1(RAMFs) or 2(Others) heads on floppies
        TEQ     r0, #1
        TEQNE   r0, #2
 [ DebugL
        DREG    r0,"Heads="
        BEQ     %FT01
        DLINE   "Failed on number of heads"
01
 ]
        BNE     %FT95

        Push    "R3"
        ; Check if it sanity checks as an E format floppy disc
 [ BigDisc
        MOV     r2, #0	; sector zero
	MOV	r3, #4	; byte offset 4
 |
        MOV     r2, #4	; byte disc address 4
 ]
        BL      SanityCheckEFormat
        Pull    "R3"
        BVS     %FT20

 [ DebugL
	DLINE	"It must be E format!"
 ]

        LDR     r2, [sp, #2*4]
 [ BigDir
 	LDR	lr, [r5, #DiscVersion]   ; check if it's EX or FX
 	TEQ	lr, #0
 	BEQ	%FT15

        LDRB    lr, [r5, #Density]

        TEQ     lr, #Quad
        baddr   r1, EXFormat_DescribeTag, NE
        baddr   r1, FXFormat_DescribeTag, EQ
        BL      CopyFormatName

	B	%FT85

15
 ]

        LDRB    lr, [r5, #Density]

        TEQ     lr, #Quad
        baddr   r1, EFormat_DescribeTag, NE
        baddr   r1, FFormat_DescribeTag, EQ
        BL      CopyFormatName

        B       %FT85

20
        ; Turn side sequencing on for FileCore L format floppies
        BL      EnsureSequencedSides

        ; Side sequencing only works with a correct disc size...
        ADD     r0, r0, #1              ; Number of platters
        LDRB    r1, [r5, #SectorSize]
        MOV     r0, r0, ASL r1          ; Size of a cylinder-sector
        LDRB    r1, [r5, #SecsPerTrk]
        MUL     r0, r1, r0              ; Size of a cylinder
        MOV     r0, r0, ASL #4          ; *16
        ADD     r0, r0, r0, ASL #2      ; *5   =*80
        STR     r0, [r5, #DiscSize]
 [ BigDisc
	MOV	r0, #0
	STR	r0, [r5, #DiscSize2]
   [ BigShare
        STR     r0, [r5, #ShareSize]    ; sharing unit always 0 for floppies
   ]
 ]

        ; Check for L format (much more strict about what's OK)
        BL      SanityCheckLFormat
        BVS     %FT30
 [ BigDisc
	LDR	r0, [r5, #DiscSize2]
	MOVS	r0, r0
	BNE	%FT30				; can't be L format - far too big!
 ]
        LDR     r0, [r5, #DiscSize]
        LDR     lr, =L_Size + 4*32*256          ; Allow up to 4 extra tracks worth - beyond that and a frigged format won't work
        CMP     r0, lr

        LDRLS   r2, [sp, #2*4]
        baddr   r1, LFormat_DescribeTag, LS
        BLLS    CopyFormatName

        BLS     %FT85

30
        ; Turn side interleaving on for checking FileCore D format floppies
        BL      EnsureInterleavedSides

        ; Check for D (old map) format disc
        BL      SanityCheckDFormat
        BVS     %FT85
 [ BigDisc
	LDR	r0, [r5, #DiscSize2]
	MOVS	r0, r0
	BNE	%FT75				; too big
 ]
        LDR     r0, [r5, #DiscSize]
        LDR     lr, =D_Size + 4*10*1024         ; Allow up to 4 extra tracks worth - beyond that and a frigged format won't work
        CMP     r0, lr

        LDRLS   r2, [sp, #2*4]
        baddr   r1, DFormat_DescribeTag, LS
        BLLS    CopyFormatName

75
        SETV    HI

85
        BVS     %FT95
 [ DebugL
        DLINE   "Its a floppy!"
 ]
        LDR     r2, =FileType_FileCoreFloppyDisc
        STR     r2, [sp, #2*4]          ; Returned disc type
        MOV     r0, #Service_Serviced
        STR     r0, [sp, #1*4]

95
 [ DebugL
        BVC     %FT01
        DLINE   "Failed to check FileCore floppy disc"
01
 ]
        CLRV
        Pull    "r0,r1,r2,r3,r8,r12,pc"

        LTORG

; ========================
; IdentifyFileCoreHardDisc
; ========================
;entry
;  r1 = Service_IdentifyDisc (&69)
;  r5 = Pointer to disc record
;  r6 = Sector cache handle
;  r8 = Pointer to FileCore instance private word to use
;  r12 = Pointer to FileCore instance private word to use
;
;exit
;If the format has been identified:
;  r1 = Service_Serviced
;  r2 = Filetype number for given disc format.
;  r5 = Pointer to disc record, which has been modified
;  r6 = New sector cache handle
;  r8 unchanged
;  r12 unchanged
;Otherwise:
;  r1 = Service_IdentifyDisc
;  r5 = Pointer to disc record, which may have been modified
;  r6 = New sector cache handle
;  r8 unchanged
;  r12 unchanged

IdentifyFileCoreHardDisc ROUT
        Push    "r0,r2,r3,r4,r5,r7-r12,lr"
 [ DebugL
        DLINE   "Identifying a hard disc"
 ]

        ; Convert disc record to non-sequenced sides
        BL      EnsureInterleavedSides

        BL      SanityCheckBadBlockList
        BVS     %FT90
 [ BigDisc
	LDRB	lr, [r5, #SectorSize]		; for conversion from byte to sector
	MOV	r3, #DefectListDiscAdd		; disc addr of boot block...
	MOV	r2, r3, LSR lr			; ...in sector form
	SUB	r3, r3, r2, LSL lr		;
	ADD	r3, r3, #DefectStruc		; offset of disc record
 |
        LDR     r2, =DefectListDiscAdd + DefectStruc
 ]
        BL      SanityCheckEFormat
        LDRVC   r2, [sp, #1*4]
 [ BigDir
	BVS	%FT01
	LDR	lr, [r5, #DiscVersion]
	TEQS	lr, #0
	baddr	r1, FFormat_DescribeTag, EQ
	baddr	r1, FXFormat_DescribeTag, NE
01
 |
        baddr   r1, FFormat_DescribeTag, VC
 ]
        BLVC    CopyFormatName
        LDRVC   r2, =FileType_FileCoreHardDisc
        BVC     %FT90
        BL      SanityCheckDFormat
        LDRVC   r2, [sp, #1*4]
        baddr   r1, DFormat_DescribeTag, VC
        BLVC    CopyFormatName
        LDRVC   r2, =FileType_FileCoreHardDisc
90
 [ DebugL
        BVC     %FT01
        DLINE   "Failed to check FileCore hard disc"
        B       %FT02
01
        DLINE   "It's a hard disc!"
02
 ]
        STRVC   r2, [sp, #1*4]
        MOVVC   r1, #Service_Serviced
        CLRV
        Pull    "r0,r2,r3,r4,r5,r7-r12,pc"

        LTORG

; ==============
; CopyFormatName
; ==============
;
; entry
;  r1 = pointer to tag
;  r2 = buffer (0 if no buffer)
;  r3 = buffer length
;
; exit
;  flags etc preserved
CopyFormatName ROUT
        Push    "r0-r8,lr"
        SavePSR r8
        TEQ     r2, #0
        BEQ     %FT95

        SUB     sp, sp, #16
        MOV     r0, sp
        ADRL    r1, message_filename
        MOV     r2, #0
        SWI     XMessageTrans_OpenFile
        BVS     %FT90

        MOV     r0, sp
        ADD     lr, sp, #16+1*4
        LDMIA   lr, {r1-r3}
        MOV     r4, #0
        MOV     r5, #0
        MOV     r6, #0
        MOV     r7, #0
        SWI     XMessageTrans_Lookup

        MOV     r0, sp
        SWI     XMessageTrans_CloseFile

90
        ADD     sp, sp, #16
95
        RestPSR r8,,f
        Pull    "r0-r8,pc"

; =======================
; SanityCheckBadBlockList
; =======================
;
; entry
;  r5 = pointer to disc record
;  r6 = sector cache handle
;  r12 = Pointer to FileCore instance private word to use
;
; exit
;  r6 = new sector cache handle
;  r12 = Unchanged
;  VC if OK
;  VS if bad
;
SanityCheckBadBlockList ROUT
 [ {TRUE}
	CLRV
	MOV	pc,lr
 |
        Push    "r0-r4,r5,r7-r12,lr"
        SUB     sp, sp, #SzDefectList

 [ DebugL
        DLINE   "Sanity checking bad block list"
 ]

 [ BigDisc :LAND: {FALSE}
        LDR     r2, [r5, #RootDir]		; to get drive number
        AND     r2, r2, #DiscBits
	MOV	r3, #DefectListDiscAdd		; disc addr of defect list
	LDRB	lr, [r5, #SectorSize]
        ORR     r2, r2, r3, LSR lr		; actual disc addr to read from
	MOV	r4, r3, LSR lr			; sector align disc addr
	SUB	r3, r3, r4, LSL lr		; extra transfer needed
	ADD	r4, r3, #SzDefectList		; amount to transfer
        SUB	sp, sp, r3			; transfer addr
	Push	"R3"
	MOV	r3, sp
        BL      SWI_SectorDiscOp_CachedReadSectors_Myself
	Pull	"R3"
	ADD	sp, sp, r3
 |
        LDR     r2, [r5, #RootDir]
        AND     r2, r2, #DiscBits
        ORR     r2, r2, #DefectListDiscAdd
        MOV     r3, sp
        MOV     r4, #SzDefectList
        BL      SWI_DiscOp_CachedReadSectors_Myself
 ]
 [ DebugL
        BVC     %FT01
        ADD     r1, r0, #4
        DSTRING r1, "Failed on reading:"
01
 ]
        BVS     %FT90

        MOV     r0, sp
        MOV     r1, #SzDefectList
        BL      CheckSum
 [ DebugL
        BVC     %FT01
        DLINE   "Failed on check sum"
01
 ]

90
 [ DebugL
        BVC     %FT01
        DLINE   "Failed to check bad block list"
01
 ]
        ADD     sp, sp, #SzDefectList
        Pull    "r0-r4,r7-r12,pc"
 ]

        LTORG

; ==================
; SanityCheckEFormat
; ==================
;
; entry
 [ BigDisc
;  r2 = disc address of sector containing boot record
;  r3 = offset within sector of boot record (word aligned)
 |
;  r2 = disc address of boot record (without disc number)
 ]
;  r5 = pointer to disc record
;  r6 = sector cache handle
;  r12 = Pointer to FileCore instance private word to use
;
; exit
;   r6 = new sector cache handle
;   r12 = unchanged
;  AND
;   VC: Matches OK
;   VS: Mismatch and r0 does _not_ point to an error
;
SanityCheckEFormat ROUT
        Push    "lr"

 [ DebugL
        DLINE   "Sanity checking E format"
   [ BigDisc
	DREG	r2, "Boot record sector="
	DREG	r3, "Boot record offset="
   ]
 ]

        ; Sanity check disc record vs disc
        BL      SanityCheckEDiscRecord

        ; Read and check map from disc
        BLVC    SanityCheckNewMap

95
 [ DebugL
        BVC     %FT01
        DLINE   "Failed to check E format"
        B       %FT02
01
        DLINE   "E format is the business!"
02
 ]
        Pull    "pc"

        LTORG

; ======================
; SanityCheckEDiscRecord
; ======================
;
; entry
 [ BigDisc
;  r2 = disc address of sector containing boot record
;  r3 = offset within sector of boot record (word aligned)
 |
;  r2 = disc address of boot record (without disc number)
 ]
;  r5 = pointer to disc record
;  r6 = sector cache handle
;  r12 = Pointer to FileCore instance private word to use
;
; exit
;   r6 = new sector cache handle
;   r12 = unchanged
;  AND
;   VC: Matches OK
;   VS: Mismatch and r0 does _not_ point to an error
;
SanityCheckEDiscRecord ROUT
        Push    "r0,r1,r2,r3,r4,r5,r7,r8,r9,r10,r11,r12,lr"
 [ BigDisc
        SUB     sp, sp, #DiscRecSig2
	SUB	sp, sp, r3		; adjust for disc record offset
 |
        SUB     sp, sp, #DiscRecSig
 ]

 [ DebugL
        DLINE   "Sanity checking E disc record"
	DREG	r2, "Disc addr ="
	DREG	r3, "Offset ="
	DREG	sp, "SP ="
 ]

        MOV     r1, #CachedReadSecsOp
        LDR     r14, [r5, #RootDir]
        AND     r14, r14, #DiscBits
        ORR     r2, r2, r14

 [ BigDisc
        MOV     r4, #DiscRecSig2	; length we want
	ADD	r4, r4, r3		; actual transfer length to compensate for offset
	Push	"R3"
        ADD     r3, sp, #4
        BL      SWI_SectorDiscOp_CachedReadSectors_Myself
	Pull	"R3"
	ADD	sp, sp, r3	; pointer to disc record actual data
 |
        MOV     r3, sp
        MOV     r4, #DiscRecSig
        BL      SWI_DiscOp_CachedReadSectors_Myself
 ]

 [ DebugL
        BVC     %FT01
        ADD     r1, r0, #4
        DSTRING r1, "Failed on reading"
01
 ]
        BVS     %FT90

        ; Sanity check disc record vs disc

        ; Check sectorsize, secpertrk, heads and density all match the real values
        ASSERT  (SectorSize :MOD: 4) = 0
        ASSERT  SecsPerTrk = SectorSize+1
        ASSERT  Heads = SecsPerTrk+1
        ASSERT  Density = Heads+1
        LDR     r0, [r5, #SectorSize]
        LDR     r1, [sp, #SectorSize]

        ; On floppy discs ignore SecsPerTrk to robustify against copy-protection schemes
        LDR     lr, [r5, #RootDir]
        TST     lr, #bit31
        EOR     lr, r0, r1
        BICNE   lr, lr, #&0000ff00
        TEQ     lr, #0

 [ DebugL
        BEQ     %FT01
        DREG    r0,"Failed on mismatched sector sizes etc: Rec=",cc
        DREG    r1, " boot="
01
 ]
        BNE     %FT85

 [ BigMaps
        ; Check 0 < LinkBits < 17
        LDRB	r0, [sp, #LinkBits]
        CMP     r0, #19

 [ DebugL
        BLS     %FT01
        DLINE   "Failed on LinkBits >= 20"
01
 ]

 |
        ; Check 0 < LinkBits < 16
        LDRB    r0, [sp, #LinkBits]
        CMP     r0, #15
 [ DebugL
        BLS     %FT01
        DLINE   "Failed on LinkBits >= 16"
01
 ]

 ]
        BHI     %FT85
        CMP     r0, #0
 [ DebugL
        BNE     %FT01
        DLINE   "Failed on LinkBits = 0"
01
 ]
        BEQ     %FT85

        ; Check sufficient link bits for max number of fragments
        LDRB    r0, [sp, #SectorSize]
        MOV     r1, #8                  ; 8 bits per byte
        MOV     r1, r1, ASL r0          ; bits per sector
        ASSERT  (ZoneSpare :MOD: 4)=2
        LDR     r0, [sp, #ZoneSpare - 2]
        SUB     r1, r1, r0, LSR #16     ; map bits per sector
        LDRB    r0, [sp, #LinkBits]
        ADD     r0, r0, #1
        DivRem  r2, r1, r0, lr          ; r2 = max objects per zone
 [ BigMaps
        LDRB    r0, [sp, #Zones]
        LDRB	r1, [sp, #Zones2]	; r1 is the target for the MUL below
        ADD	r0, r0, r1, LSL #8
 |
        LDRB    r0, [sp, #Zones]
 ]
 [ DebugL
 	DREG	r0, "zones: "
 ]
        MUL     r1, r2, r0              ; r1 = max objects in map
        LDRB    r0, [sp, #LinkBits]
 [ DebugL
 	DREG	r0, "linkbits: "
 ]
        MOVS    r14, r1, LSR r0
 [ DebugL
        BEQ     %FT01
        DLINE   "Failed on 2^LinkBits < Max Total objects"
01
 ]
        BNE     %FT85                   ; If shifting right by linkbits leaves a non-0
                                        ; answer, then there aren't enough link bits!

        ; Check sufficient link bits for free space list in a sector
        LDRB    r0, [sp, #SectorSize]
        ADD     r0, r0, #3              ; 2^3 = 8 = bits per byte
        LDRB    r2, [sp, #LinkBits]

 [ BigMaps
        ; if BigMaps then LinkBits can be more than MaxFreeLink, so test agains
        ; MaxFreeLink (we're being paranoid here, since maximum sector is 1024
        ; bytes, needing 13 link bits)

        CMP	r2, #MaxFreeLinkBits
        MOVHI	r2, #MaxFreeLinkBits
 ]

        CMP     r2, r0
 [ DebugL
        BHS     %FT01
        DLINE   "Failed on LinkBits < Zone length in bits"
01
 ]
        BLO     %FT85                   ; Definitely not enough

        ; Check RAskew not being silly
        LDRB    r0, [sp, #RAskew]
        LDRB    r2, [sp, #SecsPerTrk]
        CMP     r0, r2
 [ DebugL
        BLO     %FT01
        DLINE   "Failed on RASkew >= SecsPerTrk"
01
 ]
        BHS     %FT85                   ; skew >= secspertrk is silly!

 [ BigShare
        ; Check RootDir is sensible:
        ; Must be &000002nn where nn=(2*Zones)>>ShareSize+1
 [ BigMaps

 	LDRB	r1, [sp, #LinkBits]
 	CMP	r1, #15
 	BHI	%FT10

        LDRB	r1, [sp, #DiscVersion]
	TEQS	r1, #0
        BNE	%FT10			; don't sanity check rootdir address


 ]

 [ BigMaps
 	LDRB	r1, [sp, #Zones]
 	LDRB	r0, [sp, #Zones2]	; r0 due for corruption later
 	ADD	r1, r1, r0,LSL #8
 |
        LDRB    r1, [sp, #Zones]
 ]
        MOV     r1, r1, ASL #1
        LDRB    r0, [sp, #ShareSize]    ; factor in sharesize
        MOV     lr, #1
        ADD     r1, r1, lr, LSL r0
        SUB     r1, r1, #1
        MOV     r1, r1, LSR r0
        ADD     r1, r1, #1
        ADD     r1, r1, #&200
        LDR     r0, [sp, #RootDir]
        TEQ     r0, r1
 |
        ; Check RootDir is sensible:
        ; Must be &000002nn where nn=2*Zones+1
 [ BigMaps
        LDRB    r1, [sp, #Zones]
        LDRB	r0, [sp, #Zones2]	; r0 due to be corrupted
        ADD	r1, r1, r0, LSL #8
 |
        LDRB    r1, [sp, #Zones]
 ]
        MOV     r1, r1, ASL #1
        ADD     r1, r1, #1
        ADD     r1, r1, #&200
        LDR     r0, [sp, #RootDir]
        TEQ     r0, r1
 ]
 [ DebugL
        BEQ     %FT01
        DREG    r1, "Failed on RootDir != "
01
 ]
        BEQ     %FT10

        ; or, if Zones == 1, then &000002nn where nn = (&e00 + 1<<SectorSize - 1)>>SectorSize + 1
        LDRB    r1, [sp, #Zones]
        TEQ     r1, #1
 [ BigMaps
 	LDREQB	r1, [sp, #Zones2]
 	TEQEQ	r1, #0		; have to also check that Zones2 is 0
 ]
        BNE     %FT85

        MOV     r14, #1
        LDRB    r1, [sp, #SectorSize]
        MOV     r14, r14, ASL r1
        ADD     r14, r14, #DefectListDiscAdd + SzDefectList
        SUB     r14, r14, #1
        MOV     r14, r14, LSR r1
        ADD     r14, r14, #1
        ORR     r14, r14, #&200
        TEQ     r0, r14
 [ DebugL
        BEQ     %FT01
        DREG    r1, "Failed on RootDir != "
01
 ]
        BNE     %FT85

10

        ; Check disc size:
        ; Must be > ((Zones-1)*(8<<SectorSize-ZoneSpare)-Zone0Bits)<<BitSize
 [ {FALSE}
        ; (this check should not be made as may be partitioned for UNIX)
        ; Must be < 512M (due to duff DiscOp interface)
 ]
; check for Big disc on Small filing system
 [ BigDisc
        LDRB    r1, [sp, #BigFlag]      ; check if its a big disc
	TSTS	r1, #BigFlagBit
        BEQ     %FT01
        LDR     r1, [r12]
        LDR     r1, [r1,#:INDEX:FS_Flags]
        TST     r1, #BigDiscSupport
        BEQ     %FT85                   ; small filing system, big disc

01      ; not big or big on big filing system
 ]
        MOV     r0, #8
        LDRB    r1, [sp, #SectorSize]
        MOV     r0, r0, ASL r1
        ASSERT  (ZoneSpare :MOD: 4)=2
        LDR     r1, [sp, #ZoneSpare - 2]
        SUB     r0, r0, r1, LSR #16
 [ BigMaps
	LDRB	r1, [sp, #Zones]
	LDRB	lr, [sp, #Zones2]	; lr is safe to use
	ADD	r1, r1, lr, LSL #8
 |
        LDRB    r1, [sp, #Zones]
 ]
        SUB     r1, r1, #1
        MUL     r0, r1, r0
        SUB     r0, r0, #Zone0Bits
        LDRB    r1, [sp, #BitSize]
 [ BigDisc
; first, get the comparison size in sectors
	LDRB	lr, [sp, #SectorSize]
	SUBS	r1, r1, lr
        MOVPL   r0, r0, LSL r1
	RSBMI	r0, r0, #0
        MOVMI   r0, r0, LSR r1
; then the disc size in sectors
	LDR	r1, [sp, #DiscSize]
	MOV	r1, r1, LSR lr
	LDR	r2, [sp, #DiscSize2]
 [ DebugL

	DREG	r2, "Discsize2 was "
 ]
	RSB	lr, lr, #32
	ORR	r1, r1, r2, LSL lr	; now full DiscSize in sectors in r1
	CMP	r1, r0
 |
        MOV     r0, r0, ASL r1
        LDR     r1, [sp, #DiscSize]
        CMP     r1, r0
 ]
 [ DebugL
        BGT     %FT01
        DREG    r0, "Failed on Disc Size (signed)<= "
01
 ]
        BLE     %FT85
 [ {FALSE}
        ; Don't check for upper limit - its OK to be bigger
        CMP     r1, #512*1024*1024
 [ DebugL
        BLO     %FT01
        DLINE   "Failed on Disc Size > 512M"
01
 ]
        BHS     %FT85
 ]

        ; All checked out - this disc record is cool!
        ; Copy the info into the r5 disc record
        ; Those fields which must be left to later are:
        ; DiscId
        ; DiscName
        ; BootOpt       (Although the byte which would be the BootOption is copied)
        ASSERT  (LinkBits :MOD: 4)=0
        ASSERT  BitSize = LinkBits+1
        ASSERT  RAskew = BitSize+1
        ASSERT  BootOpt = RAskew+1
        LDR     r0, [sp, #LinkBits]
        STR     r0, [r5, #LinkBits]
        LDRB    r0, [sp, #Zones]
        STRB    r0, [r5, #Zones]
 [ BigMaps
 	LDRB	r0, [sp, #Zones2]
 	STRB	r0, [r5, #Zones2]
 ]
        LDRB    r0, [sp, #ZoneSpare]
        STRB    r0, [r5, #ZoneSpare]
        LDRB    r0, [sp, #ZoneSpare+1]
        STRB    r0, [r5, #ZoneSpare+1]
        LDR     r0, [sp, #RootDir]
        LDR     r1, [r5, #RootDir]
        AND     r1, r1, #DiscBits
        ORR     r0, r0, r1
 [ DebugL
	DREG	r1, "DiscBits from disc record are: "
	DREG	r0, "Setting RootDir to: (Identify, 968) "
 ]
        STR     r0, [r5, #RootDir]
        LDR     r0, [sp, #DiscSize]
        STR     r0, [r5, #DiscSize]
 [ BigDisc
        LDR     r0, [sp, #DiscSize2]
        STR     r0, [r5, #DiscSize2]
   [ BigShare
        LDR     r0, [sp, #ShareSize]
        STR     r0, [r5, #ShareSize]
   ]
 ]
 [ BigDir
 	LDR	r0, [sp, #DiscVersion]
 	STR	r0, [r5, #DiscVersion]
 	LDR	r0, [sp, #RootDirSize]
 	STR	r0, [r5, #RootDirSize]
 ]
        CLRV
        B       %FT90

85
        SETV
90
 [ DebugL
        BVC     %FT01
        DLINE   "Failed to check E disc record"
01
 ]
 [ BigDisc
        ADD     sp, sp, #DiscRecSig2
 |
        ADD     sp, sp, #DiscRecSig
 ]
95
        Pull    "r0,r1,r2,r3,r4,r5,r7,r8,r9,r10,r11,r12,pc"

        LTORG

; =================
; SanityCheckNewMap
; =================
;
; entry
;  r5 -> disc record (with data from disc signature filled in)
;  r6 = cache handle
;  r12 = Pointer to FileCore instance private word to use
;
; on exit
;  r5 unchanged
;  r6 = new cache handle
;  r12 = unchanged
;  VC => Map checked OK
;  VS => Map duff
;
SanityCheckNewMap ROUT
        Push    "r0-r5,r7-r10,lr"

 [ DebugL
        DLINE   "Sanity checking new map"
 ]

        LDRB    r4, [r5, #SectorSize]
        MOV     lr, #1
        SUB     sp, sp, lr, ASL r4

 [ BigMaps
        LDRB    r9, [r5, #Zones]
        LDRB	r7, [r5, #Zones2]
        ADD	r9, r9, r7, LSL #8
        LDRB    r7, [r5, #SectorSize]
 |
        LDRB    r7, [r5, #SectorSize]
        LDRB    r9, [r5, #Zones]
 ]
        BL      MapDiscAdd
        MOV     r7, r2

        ; Offset to start of map block (chooses between the two map copies)
        MOV     r8, #0

10
        ; Sector offset within map copy
        MOV     r9, #0

        ; Current EOR of cross checks
        MOV     r10, #0

20
        ; Read a sector
        ADD     r2, r7, r8
        LDRB    r4, [r5, #SectorSize]
 [ BigDisc
        ADD     r2, r2, r9
 |
        ADD     r2, r2, r9, ASL r4
 ]
        MOV     r3, sp
        MOV     lr, #1
        MOV     r4, lr, ASL r4
 [ BigDisc
        BL      SWI_SectorDiscOp_CachedReadSectors_Myself
 |
        BL      SWI_DiscOp_CachedReadSectors_Myself
 ]
 [ DebugL
        BVC     %FT01
        ADD     r1, r0, #4
        DSTRING r1, "(Read failed:"
01
 ]
        BVS     %FT30

        ; Make a simple test on the free link
        LDRB    r0, [sp, #FreeLink+1]
        TST     r0, #&80
 [ DebugL
        BNE     %FT01
        DLINE   "(Top bit of free link is clear)"
01
 ]
        BEQ     %FT30

        ; Check it
        MOV     r0, sp
        LDRB    r1, [r5, #SectorSize]
        MOV     lr, #1
        MOV     r1, lr, ASL r1
        BL      NewCheck
 [ DebugL
        BEQ     %FT01
        DLINE   "(NewCheck failed)"
01
 ]
        BNE     %FT30

        ; Construct the cross check
        LDRB    r0, [sp, #CrossCheck]
        EOR     r10, r10, r0

        ; Advance to the next sector of the map
        ADD     r9, r9, #1
 [ BigMaps
        LDRB    r0, [r5, #Zones]
        LDRB	r2, [r5, #Zones2]	; r2 should be ok here
        ADD	r0, r0, r2, LSL #8
 |
        LDRB    r0, [r5, #Zones]
 ]
        CMP     r9, r0
        BLO     %BT20

        ; Check the cross check
        TEQ     r10, #&ff
 [ DebugL
        BEQ     %FT01
        DREG    r10, "(Cross check failed):"
01
 ]
        BEQ     %FT40

30
        ; A failure has happened

        ; If not on first copy of map, then map is bad, so give up!
        TEQ     r8, #0
 [ DebugL
        BEQ     %FT01
        DLINE   "Failed on both map copies"
01
 ]
        BNE     %FT85

        ; Try on the second map copy
        LDRB    r8, [r5, #Zones]
 [ BigMaps
 	LDRB	r0, [r5, #Zones2]
 	ADD	r8, r8, r0, LSL #8
 ]
        LDRB    r0, [r5, #SectorSize]
 [ BigDisc
 |
        MOV     r8, r8, ASL r0
 ]

        B       %BT10

40
        ; Map cross-checks OK


        ; Check the disc record in the first map sector against
        ; the disc's disc record.

        ADD     r2, r7, r8
        LDRB    r4, [r5, #SectorSize]

        MOV     r3, sp
        MOV     lr, #1
        MOV     r4, lr, ASL r4
 [ BigDisc
        BL      SWI_SectorDiscOp_CachedReadSectors_Myself
 |
        BL      SWI_DiscOp_CachedReadSectors_Myself
 ]
 [ DebugL
        BVC     %FT01
        ADD     r1, r0, #4
        DSTRING r1, "Failed on reread of 1st map block"
01
 ]
        BVS     %FT90

        ; Cross check the boot disc record with the map 1st sector
        ; disc record. Those fields which should match are:
        ; sector size
        ; sectors per track
        ; heads
        ; density
        ; fragment id length
        ; bytes per map bit
        ; RASkew
        ; lowsector
        ; zones
        ; zone spare
        ; root directory
        ; disc size
        ; Those fields which don't match are:
        ; boot option
        ; disc id
        ; disc name
        ADD     r4, sp, #ZoneHead
        MOV     r14, r5

	LDRB	r0,[r4,#Zones]		; this is spurious!

        ASSERT  SectorSize=0
        ASSERT  SecsPerTrk=1
        ASSERT  Heads=2
        ASSERT  Density=3
        ASSERT  LinkBits=4
        ASSERT  BitSize=5
        ASSERT  RAskew=6
        ASSERT  BootOpt=7
        LDMIA   r4!, {r0-r1}
        LDMIA   r14!, {r2-r3}
        TEQ     r0, r2
 [ DebugL
        BEQ     %FT01
        DREG    r0,"DHSS:",cc
        DREG    r2,"!="
01
 ]
        EOR     r0, r1, r3
        BICS    r0, r0, #&ff000000      ; Boot option missing from boot record (pervy eh?)
 [ DebugL
        BEQ     %FT01
        DREG    r1,"BRBL:",cc
        DREG    r3,"!="
01
 ]

        ASSERT  LowSector=8
        ASSERT  Zones=9
        ASSERT  ZoneSpare=10
        ASSERT  RootDir=12
        LDMEQIA r4!, {r0-r1}
        LDMEQIA r14!, {r2-r3}
        TEQEQ   r0, r2
 [ DebugL
        BEQ     %FT01
        DLINE   ".",cc
01
 ]
        BICEQ   r3, r3, #DiscBits       ; Test root dir modulo disc number
        TEQEQ   r1, r3
 [ DebugL
        BEQ     %FT01
        DLINE   ".",cc
01
 ]

        ASSERT  DiscSize=16
 [ BigDisc
	ASSERT	DiscSize2=36
 ]
        LDREQ   r0, [r4], #4
        LDREQ   r2, [r14], #4
        TEQEQ   r0, r2
 [ BigDisc
   [ BigShare
        ASSERT  ShareSize=40
	ADDEQ	r4,r4,#DiscSize2-DiscSize-4
	ADDEQ	r14,r14,#DiscSize2-DiscSize-4
        LDMEQIA r4!, {r0-r1}
        LDMEQIA r14!, {r2-r3}
        TEQEQ   r0, r2
        TEQEQ   r1, r3
   |
	ADDEQ	r4,r4,#DiscSize2-DiscSize-4
	ADDEQ	r14,r14,#DiscSize2-DiscSize-4
        LDREQ   r0, [r4], #4
        LDREQ   r2, [r14], #4
        TEQEQ   r0, r2
   ]
 ]
 [ DebugL
        BEQ     %FT01
        DLINE   ".",cc
01
 ]
 [ DebugL
        BEQ     %FT01
        DLINE   "Failed on disc record cross-check"
01
 ]
        BNE     %FT85

        ; All hunky-dory, copy over DiscId, Boot Option and Disc Name
        ASSERT  (DiscId :MOD: 4) = 0
        ASSERT  DiscName = DiscId+2
        LDR     r0, [sp, #ZoneHead + DiscId]
        STR     r0, [r5, #DiscId]
        LDR     r0, [sp, #ZoneHead + DiscId+4]
        STR     r0, [r5, #DiscId+4]
        LDR     r0, [sp, #ZoneHead + DiscId+8]
        STR     r0, [r5, #DiscId+8]
        LDRB    r0, [sp, #ZoneHead + BootOpt]
        STRB    r0, [r5, #BootOpt]
        B       %FT90

85
        SETV
90
 [ DebugL
        BVC     %FT01
        DLINE   "Failed to check new map"
01
 ]
        LDRB    r4, [r5, #SectorSize]
        MOV     lr, #1
        ADD     sp, sp, lr, ASL r4
95
        Pull    "r0-r5,r7-r10,pc"

        LTORG

; ==================
; SanityCheckLFormat
; ==================
;
; entry
;  r5 = pointer to disc record
;  r6 = sector cache handle
;  r12 = Pointer to FileCore instance private word to use
;
; exit
;   r6 = new sector cache handle
;   r12 = unchanged
;  AND
;   VC: Matches OK
;   VS: Mismatch and r0 does _not_ point to an error
;
SanityCheckLFormat ROUT
        Push    "r0,lr"
 [ DebugL
        DLINE   "Sanity checking L format"
 ]

        ; Must be lowsector=0, 2 heads, 15x256 byte sectors, and double density
        LDRB    r0, [r5, #LowSector]
        AND     r0, r0, #LowSectorMask
        TEQ     r0, #0
        BNE     %FT90
        BL      EnsureSequencedSides
        TEQ     r0, #1
 [ DebugL
        BEQ     %FT01
        DREG    r0,"Heads="
01
 ]
        BNE     %FT90
        LDRB    r0, [r5, #SecsPerTrk]
        TEQ     r0, #16
 [ DebugL
        BEQ     %FT01
        DREG    r0,"SecsPerTrk="
01
 ]
        BNE     %FT90
        LDRB    r0, [r5, #SectorSize]
        TEQ     r0, #8
 [ DebugL
        BEQ     %FT01
        DREG    r0,"SectorSize="
01
 ]
        BNE     %FT90
        LDRB    r0, [r5, #Density]
        TEQ     r0, #Double
 [ DebugL
        BEQ     %FT01
        DREG    r0,"Density="
01
 ]
        BNE     %FT90

 [ BigDisc
        ; Fake a disc size for sequence sides
        MOV     r0, #640*1024
        STR     r0, [r5, #DiscSize]

        ; Upper word of disc size
        MOV     r0, #0
	STR	r0, [r5, #DiscSize2]
	; r0 is already 0 for SanityCheckOldMap
 |
        ; Fake a disc size for sequence sides
        MOV     r0, #640*1024
        STR     r0, [r5, #DiscSize]

        ; Read and check map from disc
        MOV     r0, #0
 ]
        BL      SanityCheckOldMap
 [ DebugL
        BVC     %FT01
        DLINE   "OldMapBroken"
01
 ]
        BVC     %FT95

90
        SETV
95
 [ DebugL
        BVC     %FT01
        DLINE   "Failed to check L format"
        B       %FT02
01
        DLINE   "L format is the business!"
02
 ]
        Pull    "r0,pc"

        LTORG

; ==================
; SanityCheckDFormat
; ==================
;
; entry
;  r5 = pointer to disc record
;  r6 = sector cache handle
;  r12 = Pointer to FileCore instance private word to use
;
; exit
;   r6 = new sector cache handle
;   r12 = unchanged
;  AND
;   VC: Matches OK
;   VS: Mismatch and r0 does _not_ point to an error
;
SanityCheckDFormat ROUT
        Push    "lr"
 [ DebugL
        DLINE   "Sanity checking D format"
 ]

        ; Read and check map from disc
        MOV     r0, #1
        BL      SanityCheckOldMap

95
 [ DebugL
        BVC     %FT01
        DLINE   "Failed to check D format"
        B       %FT02
01
        DLINE   "D format is the business!"
02
 ]
        Pull    "pc"

        LTORG

; =================
; SanityCheckOldMap
; =================
;
; entry
;  r0 =flags:
;       if <> 0 'Directories are large (77 entries)' and at D_Root
;  r5 -> disc record (with data from disc signature filled in)
;  r6 = cache handle
;  r12 = Pointer to FileCore instance private word to use
;
; on exit
;  r5 unchanged
;  r6 = new cache handle
;  r12 = unchanged
;  VC => Map checked OK and disc name and size copied to disc record
;  VS => Map duff
;
SanityCheckOldMap ROUT
        Push    "r0-r4,r7,lr"
        SUB     sp, sp, #SzOldFs

 [ DebugL
        DLINE   "Sanity checking old map"
 ]

        LDR     r7, [r5, #RootDir]
        AND     r7, r7, #DiscBits

        ; Read the 1st map copy
        MOV     r2, r7
        MOV     r3, sp
        MOV     r4, #SzOldFs
        BL      SWI_DiscOp_CachedReadSectors_Myself

 [ DebugL
        DLINE   "Point A"
        BVC     %FT01
        ADD     r1, r0, #4
        DSTRING r1, "Failed on read map (1st copy):"
01
 ]
        BVS     %FT90

        MOV     r0, sp
        MOV     r1, #SzOldFs/2
        BL      CheckSum
 [ DebugL
        DLINE   "Point B"
        BVC     %FT01
        DLINE   "Failed on check sum, 1st half"
01
 ]
        BVS     %FT90

        ; CheckSum 2nd section of old map
        ADD     r0, sp, #SzOldFs/2
        MOV     r1, #SzOldFs/2
        BL      CheckSum
 [ DebugL
        DLINE   "Point D"
        BVC     %FT01
        DLINE   "Failed on check sum, 2nd half"
01
 ]
        BVS     %FT90

        ; CheckSum clean - sanity check free space list

        ; r0 = pointer into free list
        ; r1 = end of previous free block (starts at end of root dir) (in 256-bytes)
        ; r3 = disc size (in 256-bytes)
        ; r4 = Number of free space entries to go
        ADD     r0, sp, #FreeStart
        LDR     lr, [sp, #SzOldFs]
        TEQ     lr, #0
        MOVEQ   r1, #L_Root + OldDirSize
        MOVNE   r1, #D_Root + NewDirSize
        MOV     r1, r1, LSR #8
        SUB     r1, r1, #1
        ASSERT  (OldSize :MOD: 4) = 0
        LDR     r3, [sp, #OldSize]
        BIC     r3, r3, #&ff000000      ; r3 = disc size/256
        CMP     r3, #8+2                ; 2*256 for map, 8*256 for large (new) directory
        SETV    LO
 [ DebugL
        BVC     %FT01
        DREG    r3, "Disc size too small:"
01
 ]
        BVS     %FT90

        LDRB    r4, [sp, #FreeEnd]
        B       %FT20

10
        ; Construct Start
        LDRB    r2, [r0, #0]
        LDRB    lr, [r0, #1]
        ORR     r2, r2, lr, ASL #8
        LDRB    lr, [r0, #2]
        ORR     r2, r2, lr, ASL #16

        ; If Start <= previous end then bad map
        CMP     r2, r1
 [ DebugL
        BHI     %FT01
        DREG    r2, "Failed on Start(",cc
        DREG    r1, ")<=Previous end(",cc
        DLINE   ")"
01
 ]
        SETV    LS
        BVS     %FT90

        ; Construct End
        ADD     r0, r0, #FreeLen - FreeStart
        LDRB    lr, [r0, #0]
        ADD     r1, r1, lr
        LDRB    lr, [r0, #1]
        ADD     r1, r1, lr, ASL #8
        LDRB    lr, [r0, #2]
        ADD     r1, r1, lr, ASL #16
        ADD     r0, r0, #FreeStart - FreeLen + 3

        ; If End>DiscSize then puke
        CMP     r1, r3
 [ DebugL
        BLS     %FT01
        DREG    r1, "Failed on End(",cc
        DREG    r3, ")>Disc size(",cc
        DLINE   ")"
01
 ]
        SETV    HI
        BVS     %FT90

20
        ; Count down to the end
        SUBS    r4, r4, #3
        BHI     %BT10

        ; Copy OldBoot to BootOpt
        LDRB    r0, [sp, #OldBoot]
        STRB    r0, [r5, #BootOpt]

        ; Copy the OldId to DiscId
        LDRB    r0, [sp, #OldId]
        STRB    r0, [r5, #DiscId]
        LDRB    r0, [sp, #OldId+1]
        STRB    r0, [r5, #DiscId+1]

        ; Copy the name to the disc record
        LDRB    r0, [sp, #OldName0+0]
        STRB    r0, [r5, #DiscName+0]
        LDRB    r0, [sp, #OldName1+0]
        STRB    r0, [r5, #DiscName+1]
        LDRB    r0, [sp, #OldName0+1]
        STRB    r0, [r5, #DiscName+2]
        LDRB    r0, [sp, #OldName1+1]
        STRB    r0, [r5, #DiscName+3]
        LDRB    r0, [sp, #OldName0+2]
        STRB    r0, [r5, #DiscName+4]
        LDRB    r0, [sp, #OldName1+2]
        STRB    r0, [r5, #DiscName+5]
        LDRB    r0, [sp, #OldName0+3]
        STRB    r0, [r5, #DiscName+6]
        LDRB    r0, [sp, #OldName1+3]
        STRB    r0, [r5, #DiscName+7]
        LDRB    r0, [sp, #OldName0+4]
        STRB    r0, [r5, #DiscName+8]
        LDRB    r0, [sp, #OldName1+4]
        STRB    r0, [r5, #DiscName+9]

        ; Copy disc size to disc record
        MOV     r3, r3, ASL #8
        STR     r3, [r5, #DiscSize]
 [ BigDisc
	MOV	r3, #0
	STR	r3, [r5, #DiscSize2]
 ]

90
 [ DebugL
        BVC     %FT01
        DLINE   "Failed to check old map"
        B       %FT02
01
        DLINE   "Old map is the business!"
02
 ]
        ADD     sp, sp, #SzOldFs
95
        Pull    "r0-r4,r7,pc"

        LTORG

; ====================
; EnsureSequencedSides
; ====================
;
; In
;    R5 = pointer to disc record
; Out
;    R0 = number of heads (adjusted for sequence sides)
;    R5 = pointer to sequence sided disc record
;
EnsureSequencedSides ROUT
        LDRB    r0, [r5, #LowSector]
        TST     r0, #SequenceSides
        ORR     r0, r0, #SequenceSides
        STRB    r0, [r5, #LowSector]
        LDRB    r0, [r5, #Heads]
        SUBEQ   r0, r0, #1
        STREQB  r0, [r5, #Heads]
        MOV     pc, lr

; ======================
; EnsureInterleavedSides
; ======================
;
; In
;    R5 = pointer to disc record
; Out
;    R0 = number of heads (adjusted for interleaved sides)
;    R5 = pointer to sequence sided disc record
;
EnsureInterleavedSides ROUT
        LDRB    r0, [r5, #LowSector]
        TST     r0, #SequenceSides
        BIC     r0, r0, #SequenceSides
        STRB    r0, [r5, #LowSector]
        LDRB    r0, [r5, #Heads]
        ADDNE   r0, r0, #1
        STRNEB  r0, [r5, #Heads]
        MOV     pc, lr

; ===================================
; SWI_DiscOp_CachedReadSectors_Myself
; ===================================
;
; In
;       r2-r4 DiscOp parameters
;       r5 = disc record
;       r6 = cache
;       r12 = private workspace pointer
;
; Out
;       r12 = unchanged
;       results of DiscOp
;
SWI_DiscOp_CachedReadSectors_Myself ROUT
        Push    "r1,r7-r12,lr"
 [ Debug2 :LOR: Debug2D
        DREG    r1, "DiscOpMyself(",cc
        DREG    r2, ",",cc
        DREG    r3, ",",cc
        DREG    r4, ",",cc
        DLINE   ")"
 ]
        MOV     r11, sp
        MOV     r1, r2, LSR #29
        BIC     r2, r2, #DiscBits
        MOV     lr, #0
        Push    "r1,r2,lr"
        MOV     r8, r12
        MOV     r2, sp
        MOV     r1, #CachedReadSecsOp :OR: 1:SHL:6      ; Ignore escape
        SWI     XFileCore_DiscOp64
 [ DebugL
        BVC     %FT01
        ADD     r0, r0, #4
        DSTRING r0, "Cached read sector error:"
        SUB     r0, r0, #4
01
 ]
        LDMIA   r2, {r2, lr}
        BIC     lr, lr, #DiscBits
        ORR     r2, lr, r2, LSL #29
        MOV     sp, r11
        Pull    "r1,r7-r12,pc"

; ===================================
; SWI_DiscOp_CachedReadSectors_Myself
; ===================================
;
; In
;       r2-r4 DiscOp parameters
;       r5 = disc record
;       r6 = cache
;       r12 = private workspace pointer
;
; Out
;       r12 = unchanged
;       results of DiscOp
;

SWI_SectorDiscOp_CachedReadSectors_Myself ROUT
        Push    "r1,r7-r12,lr"
 [ Debug2 :LOR: Debug2D
        DREG    r1, "SectorDiscOpMyself(",cc
        DREG    r2, ",",cc
        DREG    r3, ",",cc
        DREG    r4, ",",cc
        DLINE   ")"
 ]
        MOV     r11, sp
        LDRB    lr, [r5, #SectorSize]
        MOV     r1, r2, LSR #29
        BIC     r2, r2, #DiscBits
        RSB     r8, lr, #32
        MOV     r7, r2, LSL lr
        MOV     lr, r2, LSR r8
        Push    "r1,r7,lr"
        MOV     r8, r12
        MOV     r2, sp
        MOV     r1, #CachedReadSecsOp :OR: 1:SHL:6      ; Ignore escape
        SWI     XFileCore_DiscOp64
 [ DebugL
        BVC     %FT01
        ADD     r0, r0, #4
        DSTRING r0, "Cached read sector error:"
        SUB     r0, r0, #4
01
 ]
        LDRB    lr, [r5, #SectorSize]
        LDMIA   r2, {r1, r2, r7}
        RSB     r8, lr, #32
        MOV     r2, r2, LSR lr
        ORR     r2, r2, r7, LSL r8
        BIC     r2, r2, #DiscBits
        ORR     r2, r2, r1, LSL #29
        MOV     sp, r11
        Pull    "r1,r7-r12,pc"

        END