;>Commands

 TTL    "Command handling"


FsCom   bit     (31-24)
IntHelp *       (International_Help:SHR:24)

        MACRO
        ComEntry  $Com,$MinArgs,$MaxArgs,$GsTransBits,$HiBits
        ASSERT  $MinArgs<=$MaxArgs
Com$Com DCB     "$Com",0
        ALIGN
        DCD     Do$Com          - org
 =       $MinArgs
 =       $GsTransBits
 =       $MaxArgs
 =       $HiBits
        DCD     Syn$Com         - org
        DCD     Help$Com        - org
        MEND


        MACRO
        Config  $Com
        DCB     "$Com",0
        ALIGN
        DCD     Con$Com         - org
        DCD     1 :SHL: 30
        DCD     0
        DCD     ConHelp$Com     - org
        MEND

ComTab                                          ;general star commands
                                         ;filing system star commands
        ComEntry  Backup,        2,4,&F,FsCom:OR:IntHelp
        ComEntry  Bye,           0,0,0,FsCom:OR:IntHelp
        ComEntry  CheckMap,      0,1,1,FsCom:OR:IntHelp
        ComEntry  Compact,       0,1,1,FsCom:OR:IntHelp
        ComEntry  Defect,        2,2,3,FsCom:OR:IntHelp
        ComEntry  Dismount,      0,1,1,FsCom:OR:IntHelp
        ComEntry  Drive,         1,1,1,FsCom:OR:IntHelp
        ComEntry  Free,          0,1,1,FsCom:OR:IntHelp
        ComEntry  Map,           0,1,1,FsCom:OR:IntHelp
        ComEntry  Mount,         0,1,1,FsCom:OR:IntHelp
        ComEntry  NameDisc,      2,2,3,FsCom:OR:IntHelp
        ComEntry  NameDisk,      2,2,3,FsCom:OR:IntHelp
        ComEntry  Verify,        0,1,1,FsCom:OR:IntHelp
                                         ;status/configure options
 =       0
        ALIGN

; ----- FILING SYSTEM STAR COMMANDS -----

         ^ 0     ;Backup temporary workspace
SrcDrv          # 1
SrcDrvChar      # 1
DestDrv         # 1
DestDrvChar     # 1

SameDrive       # 1
BufOpt          # 1
FirstTime       # 1
                # 1

FSColonColon    # 4
DrvPlace        # 4
TotalSectors    # 4
UsedMap         # 4
ReadSectors     # 4 ; Where we're up to
AmountRead      # 4 ; How much was read this time round
WriteSectors    # 4 ; Where we're up to
BufferGotten    # 4 ; How much buffer we've got

 [ BigDisc
SrcDiscRec      # DiscRecSig2
 |
SrcDiscRec      # DiscRecSig
 ]
BackupWork      # 0


; >>>>>>>>
; DoBackup
; >>>>>>>>

BC0     DCB     "BC0",0
BC1     DCB     "BC1",0
BC2     DCB     "BC2",0
 [ {FALSE}
 ; 'Same disc' error now redundent
BC3     DCB     "BC3",0
 ]
        ALIGN

DoBackup ROUT
        Entry  Flag,Light     ;leaves SB,LR stacked
        Push    "R7-R11"

        SUB     sp, sp, #BackupWork

        MOV     r11, sp

        ; Clear out BufOpt to prevent unwanted return by OS_Exit
        MOV     lr, #0
        STR     lr, [r11, #BufOpt]

        ; Parse source drive
        MOV     r1, r0
        BL      SkipSpaces      ;(R1->R0,R1,C)
        TEQS    r0, #DiscSpecChar
        ADDEQ   r1, r1, #1
        LDRB    lr, [r1]
        STRB    lr, [r11, #SrcDrvChar]
        BL      ParseDrive      ;(R1->R0,R1,V) source drive
        BVS     BackupErrorExit
        ADD     r1, r1, #1
        STRB    r0, [r11, #SrcDrv]
        MOV     r6, r0

        ; Parse dest drive
        BL      SkipSpaces
        TEQS    r0, #DiscSpecChar
        ADDEQ   r1, r1, #1
        LDRB    lr, [r1]
        STRB    lr, [r11, #DestDrvChar]
        BL      ParseDrive      ;(R1->R0,R1,V) dest drive
        BVS     BackupErrorExit
        ADD     r1, r1, #1
        STRB    r0, [r11, #DestDrv]

        ; Ensure neither drive is a winnie
        ANDS    lr, r0, r6
        TSTS    lr, #4
        MOVEQ   r0, #BadDriveErr ;can't do winnies
        SETV    EQ
        BVS     BackupErrorExit

        ; Note down whether the drives are the same or not
        EORS    r8, r0, r6
        STRB    r8, [r11, #SameDrive]

        ; Work out which buffers we're permitting ourselves (process Q option)
        MOVEQ   r8, #(1:SHL:UseDirSpace) :OR: (1:SHL:UseWimpFree) :OR: (1:SHL:UseRmaHeap) :OR: (1:SHL:UseSysHeap) :OR: ScatterBit
        MOVNE   r8, #(1:SHL:UseScratchSpace) :OR: (1:SHL:UseSpareScreen) :OR: (1:SHL:UseWimpFree) :OR: (1:SHL:UseRmaHeap) :OR: (1:SHL:UseSysHeap) :OR: ScatterBit
        BL      SkipSpaces      ;(R1->R0,R1,C)
        TEQS    r0, #"Q"
        TEQNES  r0, #"q"
        ORREQ   r8, r8, #(1:SHL:UseApplicArea)
        ADDEQ   r1, r1, #1        ;if Q skip it
        STRB    r8, [r11, #BufOpt]

        ; Process Y option and Confirm if not present
        BL      SkipSpaces      ;(R1->R0,R1,C)
        CMPS    r0, #"Y"
        CMPNES  r0, #"y"
        BLNE    Confirm         ;(->R0,Z,V)
        BNE     BackupErrorExit

        ; Parameters now read and understood

        ; Construct <FS>::<Drv>\n
        LDR     r1, FS_Title
        BL      strlen
        ADD     r0, r3, #4+3            ; ::<drv>\n + round-up
        BIC     r0, r0, #3
        SUB     sp, sp, r0
        STR     sp, [r11, #FSColonColon]
        MOV     r2, r1
        MOV     r1, sp
        BL      strcpy
        ADD     r1, r1, r3
        MOV     r0, #":"
        STRB    r0, [r1], #1
        STRB    r0, [r1], #1
        STR     r1, [r11, #DrvPlace]
        MOV     r0, #0
        STRB    r0, [r1, #1]

        ; repeat

        MOV     r0, #1
        STRB    r0, [r11, #FirstTime]
        MOV     r0, #0
        STR     r0, [r11, #ReadSectors]
        STR     r0, [r11, #WriteSectors]

        ; {source reading part}
        ;   If source=dest:
        ;     If first time round:
        ;       Prompt user to write-protect source disc
        ;     Prompt for source disc
        ;     Wait for user key response
        ;   {source disc now in source drive}
        ;   If first time round
        ;     read file parameters for source disc
        ;     allocate space map for source disc
        ;     read space map for source disc
        ;     take a copy of the disc record for the source disc
        ;     Claim memory for transfer
        ;   read in source disc next part

        ; {dest writing part}
        ;   If source=dest
        ;     Prompt user for dest disc
        ;     Wait for user key response
        ;   {dest disc now in dest drive}
        ;   If first time round
        ;     read dest defect list
        ;     If defect list not empty
        ;       complain dest has defects
        ;     read disc record for dest disc
        ;     If dest disc record <> source disc record enough
        ;       complain source and dest don't match
        ;     Dismount dest disc
        ;   {dest disc acceptable}
        ;   Write out dest disc next part

        ; until no more to read

BackupMainLoop
        ; If first time (0<r0) OR not finished (read<total) then do another step
        LDRB    r0, [r11, #FirstTime]
        RSBS    r0, r0, #0

        LDRHS   r0, [r11, #ReadSectors]
        LDRHS   r1, [r11, #TotalSectors]
        CMPHS   r0, r1
        BHS     BackupDone

        LDRB    lr, [r11, #SameDrive]
        TEQ     lr, #0
        BNE     BackupNoPromptSource

        ; Prompt for source disc

        LDRB    lr, [r11, #FirstTime]
        TEQ     lr, #0
        baddr   r0, BC0, NE             ; PLEASE WRITE PROTECT SOURCE DISC
        BLNE    message_gswrite0
        baddr   r3, BC1, VC             ; Insert source disc in drive %0 then press SPACE bar
        LDRVCB  r0, [r11, #SrcDrvChar]
        BLVC    BackupPromptDisc
        BVS     BackupErrorExit

BackupNoPromptSource
        LDRB    lr, [r11, #FirstTime]
        TEQ     lr, #0
        BEQ     BackupScatterListPresent

        ; Read file parameters for source disc
        LDRB    r1, [r11, #SrcDrv]

 [ DebugQ
        DREG    r1, "Initial look at drive "
 ]

        BL      WhatDisc
        BVS     BackupErrorExit

 [ DebugQ
        DLINE   "Drive OK"
 ]

        ; take a copy of the disc record for the source disc
        LDMIA   r3, {r0-r2,r4-r8}
        ADD     lr, r11, #SrcDiscRec
        STMIA   lr, {r0-r2,r4-r8}
 [ BigDisc ; SBP: Thu 15th December 1994 - walked through, looks OK
	LDR	r0, [r3,#DiscSize2]
	STR	r0, [lr,#DiscSize2]

        ; Size/SectorSize (rounding up) = total sectors
; bottom 32 bits
        LDR     r0, [r3, #DiscSize]
        LDRB    lr, [r3, #SectorSize]
        MOV     r0, r0, LSR lr
	Push	"R1"
; top 32 bits
	LDR	r1, [r3, #DiscSize2]
	RSB	lr, lr, #32
	ORR	r0, r0, r1, LSL lr 	; combine them
	Pull	"R1"
        STR     r0, [r11, #TotalSectors]
 |
        ; Size/SectorSize (rounding up) = total sectors
        LDR     r0, [r3, #DiscSize]
        LDRB    lr, [r3, #SectorSize]
        MOV     r0, r0, LSR lr
        STR     r0, [r11, #TotalSectors]
 ]

        ; Work out how many words of stack space will be needed
        ADD     r0, r0, #31
        BIC     r0, r0, #31

        ; allocate space map for source disc
        SUB     sp, sp, r0, LSR #3
        STR     sp, [r11, #UsedMap]

        ; Read space map for source disc
        MOV     r5, r0, LSR #3
        LDRB    r0, [r11, #SrcDrvChar]
        LDR     lr, [r11, #DrvPlace]
        STRB    r0, [lr]
        MOV     r0, #FSControl_UsedSpaceMap
        LDR     r1, [r11, #FSColonColon]
        MOV     r2, sp
        BL      DoXOS_FSControl
        BVS     BackupErrorExit

        ; Claim memory for transfer
        LDRB    r0, [r11, #BufOpt]      ; options
        MOV     r1, #1024               ; min. = Largest sector size
 [ BigDisc; SBP: Thu 15th December 1994 - walked through, looks OK
	; make sure don't ask for silly amount of memory
	LDR	r2, [r11, #SrcDiscRec + DiscSize2]	; get top 32bits of disc size
	MOVS	r2, r2
	MOVNE	r2, #2048*1024		; limit max size
	BNE	BackupNotGigantic
        LDR     r2, [r11, #SrcDiscRec + DiscSize] ; max
	CMP	r2, #2048*1024
	MOVHI	r2, #2048*1024		; limit max size
BackupNotGigantic
 |
        LDR     r2, [r11, #SrcDiscRec + DiscSize] ; max
 ]
        MOV     r3, #1024               ; granularity
        BL      FindBuffer              ; (r0-r3,r0-r3,V)
        BVS     BackupErrorExit
        LDRB    lr, [r11, #SrcDiscRec + SectorSize]
        MOV     r2, r2, LSR lr
        STR     r2, [r11, #BufferGotten] ; in sectors

BackupScatterListPresent
        ;   Read in source disc next part
        LDRB    r4, [r11, #SrcDrv]
        MOV     r0, #ReadSecsOp
        LDR     r1, [r11, #UsedMap]
        LDR     r2, [r11, #ReadSectors]
 [ BigDisc; SBP: Thu 15th December 1994 - changed to use r5 as temp reg
          ; (r5 gets corrupted just below anyway)
; number of sectors to transfer
        LDR     r3, [r11, #SrcDiscRec + DiscSize]
        LDRB    lr, [r11, #SrcDiscRec + SectorSize]
        MOV     r3, r3, LSR lr
	LDR	r5, [r11, #SrcDiscRec + DiscSize2]
	RSB	lr, lr, #32
	ORR	r3, r3, r5, LSL lr
 |
        LDR     r3, [r11, #SrcDiscRec + DiscSize]
        LDRB    lr, [r11, #SrcDiscRec + SectorSize]
        MOV     r3, r3, LSR lr
 ]

        LDR     lr, [r11, #BufferGotten]
        CMP     r3, lr
        MOVHI   r3, lr
        ADD     r5, r11, #SrcDiscRec
 [ DebugQ
        DREG    r11, "r11 into BackupReadWriteSections is "
 ]
        BL      BackupReadWriteSections
 [ DebugQ
        DREG    r11, "r11 out of BackupReadWriteSections is "
 ]
        BVS     BackupErrorExit
        STR     r2, [r11, #ReadSectors]
        STR     r3, [r11, #AmountRead]

BackupPromptDestDisc
        ; Prompt for Dest if same drive
        LDRB    lr, [r11, #SameDrive]
        TEQ     lr, #0
        baddr   r3, BC2, EQ             ; Insert destination disc in drive %0 then press SPACE bar
        LDREQB  r0, [r11, #DestDrvChar]
 [ DebugQ
        BNE     %FT01
        DLINE   "About to prompt for destination"
01
 ]
        BLEQ    BackupPromptDisc
 [ DebugQ
        DLINE   "Dest in drive"
 ]
        BVS     BackupErrorExit

        LDRB    lr, [r11, #FirstTime]
        TEQ     lr, #0
        BEQ     BackupDestChecked

        ;     Read dest defect list
        LDR     lr, [r11, #DrvPlace]
        LDRB    r0, [r11, #DestDrvChar]
        STRB    r0, [lr]
        SUB     sp, sp, #512
        MOV     r0, #FSControl_DefectList
        LDR     r1, [r11, #FSColonColon]
        MOV     r2, sp
        MOV     r5, #512
        BL      DoXOS_FSControl
        BVS     BackupErrorExit

        ;     If defect list not empty
        LDR     r0, [sp]
        TST     r0, #DiscBits
        ;       complain dest has defects
        MOVEQ   r0, #DestDefectsErr
        SETV    EQ
        BVS     BackupErrorExit

        ADD     sp, sp, #512

        ;     Read disc record for dest disc
        LDRB    lr, [r11, #DestDrv]
        DrvRecPtr lr, lr
        LDRB    lr, [lr, #DrvsDisc]
        DiscRecPtr lr, lr

        ;     If dest disc same complain about same-discness
        ADD     r0, r11, #SrcDiscRec

 [ {FALSE}
 ; 'Same disc' checks now redundent and undesirable.

        ;     If dest disc record <> source disc record enough
        LDMIA   r0!, {r1-r4}
        LDMIA   lr!, {r6-r9}
        TEQ     r1, r6
        TEQEQ   r2, r7
        TEQEQ   r3, r8
        TEQEQ   r4, r9
        LDMEQIA r0, {r1-r4}
        LDMEQIA lr, {r6-r9}
        TEQEQ   r1, r6
        TEQEQ   r2, r7
        TEQEQ   r3, r8
        TEQEQ   r4, r9
        ;       complain source and dest don't match
        BNE     BackupDiscsDifferent

        baddr   r0, BC3
        BL      message_gswrite0
        BVS     BackupErrorExit
        B       BackupPromptDestDisc

BackupDiscsDifferent
        ; Check discs enough alike to work
        SUB     lr, lr, #4*4
        SUB     r0, r0, #4*4
 ]

        LDRB    r1, [lr, #SectorSize]
        LDRB    r2, [r0, #SectorSize]
        TEQ     r1, r2
        LDREQB  r1, [lr, #SecsPerTrk]
        LDREQB  r2, [r0, #SecsPerTrk]
        TEQEQ   r1, r2
        LDREQB  r1, [lr, #Density]
        LDREQB  r2, [r0, #Density]
        TEQEQ   r1, r2
        LDREQB  r1, [lr, #LowSector]
        LDREQB  r2, [r0, #LowSector]
        BICEQ   r1, r1, #SequenceSides
        BICEQ   r2, r2, #SequenceSides
        TEQEQ   r1, r2
        MOVNE   r0, #SizeErr
        SETV    NE
        BVS     BackupErrorExit

        ;     Dismount dest disc
        LDRB    r1, [r11, #DestDrv]
        DrvRecPtr r1, r1
        LDRB    r1, [r1, #DrvsDisc]
        BL      ActiveDismountDisc
        BVS     BackupErrorExit

BackupDestChecked

        ;   Write out dest disc next part
        LDRB    r4, [r11, #DestDrv]
        MOV     r0, #WriteSecsOp
        LDR     r1, [r11, #UsedMap]
        LDR     r2, [r11, #WriteSectors]
        LDR     r3, [r11, #AmountRead]
        ADD     r5, r11, #SrcDiscRec
        BL      BackupReadWriteSections
        BVS     BackupErrorExit
        STR     r2, [r11, #WriteSectors]

        ; Note the next loop isn't first time
        MOV     lr, #0
        STRB    lr, [r11, #FirstTime]

        B       BackupMainLoop

BackupDone
        ; Stamp the dest image now
        LDRB    r0, [r11, #DestDrvChar]
        LDR     lr, [r11, #DrvPlace]
        STRB    r0, [lr]
        MOV     r0, #FSControl_StampImage
        LDR     r1, [r11, #FSColonColon]
        MOV     r2, #1
        BL      DoXOS_FSControl
        BVS     BackupErrorExit

BackupErrorExit
 [ DebugQ
        ADD     r0, r0, #4
        DSTRING r0, "Error:"
        SUB     r0, r0, #4
 ]
        ; Free claimed resources
        BL      ReturnBuffer
        LDR     lr, [r11, #BufOpt]
        TST     lr, #1 :SHL: UseApplicArea
        BNE     QuickBack

        BLVS    FindErrBlock
        MOV     sp, r11
        ADD     sp, sp, #BackupWork
        BL      FileCoreExit
        Pull    "r7-r11,SB,pc"

QuickBack
        BVC     %FT99
        BL      FindErrBlock    ;(R0->R0,V)
        BL      FileCoreExit
        SWI     OS_GenerateError
99
        LDR     R1, ABEX
        MOV     R2, #0
        BL      FileCoreExit
        SWI     OS_Exit

ABEX    = "ABEX"

; BackupPromptDisc
;
; In
;   r0 = drive number (ASCII char)
;   r3 = message token
;
; Out
;   r0 trashed
;   disc prompted for and response received
;
BackupPromptDisc ROUT
        Push    "r0-r4,lr"              ; r0 (drive char) gets nul-terminated for free

        MOV     r0, r3
        MOV     r4, sp
        BL      message_gswrite01
        BVS     %FT95

        ; wait for a space
10
        BL      FlushAndReadChar
        BVS     %FT95
        TEQS    R0, #" "
        BNE     %BT10

95
        STRVS   r0, [sp]
        Pull    "r0-r4,pc"

; BackupReadWriteSections
;
; In
;   r0 = op (ReadSecsOp/WriteSecsOp)
;   r1 = pointer to used space map
;   r2 = position so far (in sectors)
;   r3 = RAM limit (in sectors)
;   r4 = drive
;   r5 = disc record to use
;
; Out
;   R0, V error possible
;   r2 updated
;   r3 = amount transfered
;
BackupReadWriteSections ROUT
        Push    "r0-r11,lr"

 [ DebugQ
        DREG    r0, ">BackupReadWriteSections(",cc
        DREG    r1, ",",cc
        DREG    r2, ",",cc
        DREG    r3, ",",cc
        DREG    r4, ",",cc
        DREG    r5, ",",cc
        DLINE   ")"
        DREG    sp, "SP at start="
 ]

        BL      InitScatter
        sbaddr  r11, ScatterList

        MOV     r10, #0
        MOV     r9, r0
        MOV     r8, r4

 [ BigDisc; SBP: Thu 15th December 1994 - walked thru, push/pull r7 not needed
; get number of sectors on disc
        LDR     r6, [r5, #DiscSize]
        LDRB    lr, [r5, #SectorSize]
        MOV     r6, r6, LSR lr
	LDR	r7, [r5,#DiscSize2]
	RSB	lr, lr, #32
	ORR	r6, r6, r7, LSL lr
 |
        LDR     r6, [r5, #DiscSize]
        LDRB    lr, [r5, #SectorSize]
        MOV     r6, r6, LSR lr
 ]

        ; r1 - the map
        ; r2 - position so far
        ; r3 - RAM limit (sectors)
        ; r5 - the disc record
        ; r6 - the disc size (in sectors)
        ; r8 - drive
        ; r9 - the op
        ; r10 - amount transfered
        ; r11 - scatter rover

BackupFindAnotherSection
        MOV     lr, #1
BackupFindAnotherSectionLoop
        CMP     r2, r6
        BHS     BackupSectionsExhausted

        LDRB    r0, [r1, r2, LSR #3]
 [ DebugQ :LAND: {FALSE}
        DREG    r0, ">",cc
 ]
        AND     r4, r2, #7
        ADD     r2, r2, #1
        TST     r0, lr, ASL r4
        BEQ     BackupFindAnotherSectionLoop

        SUB     r7, r2, #1              ; Start of section

        ; End where RAM or disc ends, whichever is lower
        ADD     r9, r7, r3
        CMP     r6, r9
        MOVLO   r9, r6

        ; Check if room for this section
        CMP     r2, r9
        SUBHI   r2, r2, #1
        BHI     BackupSectionsExhausted

BackupFindSectionEnd
        CMP     r2, r9
        BHS     BackupSectionExhausted

        LDRB    r0, [r1, r2, LSR #3]
 [ DebugQ
        DREG    r0, "<",cc
 ]
        AND     r4, r2, #7
        ADD     r2, r2, #1
        TST     r0, lr, ASL r4
        BNE     BackupFindSectionEnd

BackupSectionExhausted
        ; Section end found - construct operation
        SUB     lr, r2, r7
        SUB     r3, r3, lr
        ADD     r10, r10, lr

        Push    "r0-r4"
        LDR     r9, [sp, #5*4 + 0*4]    ; r0 in
        ORR     r1, r9, #ScatterBit
        SUB     r4, r2, r7
        MOV     r2, r7
        MOV     r3, r11
        LDRB    lr, [r5, #SectorSize]
        MOV     r4, r4, ASL lr
 [ BigDisc;SBP: Thu 15th December 1994 - walked thru, OK
 |
        MOV     r2, r2, ASL lr
 ]
        ORR     r2, r2, r8, ASL #(32-3)
 [ DebugQ
        DREG    r4, "Transfer length "
        DLINE   "Scatter list",cc
        Push    "r0-r2,r4"
        MOV     r2, r3
01
        LDMIA   r2!, {r0,r1}
        DREG    r0," (",cc
        DREG    r1,",",cc
        DLINE   ")",cc
        SUBS    r4, r4, r1
        STR     lr, [r0]
        SUB     r1, r1, #4
        STR     lr, [r0, r1]
        BGT     %BT01
        DLINE
        Pull    "r0-r2,r4"
 ]
 [ DebugQ
        DREG    r1, "Transfer:",cc
        DREG    r2, ",",cc
        DREG    r3, ",",cc
        DREG    r4, ",",cc
        DREG    r5, ","
 ]
        BL      RetryDriveOp
        MOV     r11, r3
        STRVS   r0, [sp]
        Pull    "r0-r4"

        BVC     BackupFindAnotherSection

BackupSectionsExhausted
        STR     r2, [sp, #2*4]
        STR     r10, [sp, #3*4]
        STRVS   r0, [sp]

 [ DebugQ
        DREG    r1, "Advance:"
        DREG    r10, "Transfer:"
        DREG    sp, "SP at end="
 ]

        Pull    "r0-r11,pc"


; >>>>>
; DoBye
; >>>>>

DoBye   ROUT
        Entry   Flag,Dormant  ;leaves SB,LR stacked
        BL      DoOsFunShutDown ;(->R0,V)
        BLVS    FindErrBlock    ;(R0->R0,V)
        BL      FileCoreExit
        Pull    "SB,PC"


; >>>>>>>>>>
; DoCheckMap
; >>>>>>>>>>

CMC0    DCB     "CMC0",0
CMC1    DCB     "CMC1",0
CMC2    DCB     "CMC2",0
CMC3    DCB     "CMC3",0
        ALIGN

DoCheckMap
        Entry   Flag,Dormant  ;leaves SB,LR stacked
        Push    "R7-R11"
        TEQS    R1, #0
        BLEQ    IdentifyCurrentDisc     ;(->R0,R3,V) if disc param missing
        BLEQ    DiscAddToRec            ;(R3->LR)
        LDREQ   R3, [LR, #RootDir]
        MOVNE   R1, R0
        MOVNE   R2, #MustBeDisc
        BLNE    FullLookUp      ;(R1,R2->R0-R6,V)
        BVS     %FT80

 [ Module_Version >= 205
        ; Reject non-FileCore discs
        BL      DiscMustBeFileCore      ;(R3->V,R0)
        BVS     %FT80
 ]

        BL      TestMap         ;(R3->Z)
        BEQ     %FT05

        baddr   r0, CMC0        ; Old Map
        BL      message_gswrite0
        B       %FT80

05
        MOV     R1, #8
        BL      CloseAllByDisc  ;(R1->R0,V)
        BVS     %FT80
        BL      DiscAddToRec    ;(R3->LR)
        MOV     R6, LR
        LDRB    LR, [R6, #DiscsDrv]
        CMPS    LR, #8
        BHS     %FT15
                        ;IF we have a map in RAM invalidate it
        DrvRecPtr  R7, LR
        LDR     R10,[R7, #DrvsFsMap]
        BIC     R10,R10,#HiFsBits
        LDRB    LR, [R6, #SectorSize]
        LDRB    R8, [R6, #Zones]
        ADD     R9, R10,R8, LSL LR
        MOV     LR, #0
10                      ;loop to clear zone flags
        STRB    LR, [R9], #1
        SUBS    R8, R8, #1
        BPL     %BT10
        LDRB    LR, [R6, #DiscFlags]
        BIC     LR, LR, #AltMapFlag
        STRB    LR, [R6, #DiscFlags]
        STR     R10,[R7, #DrvsFsMap]
15
        BL      BeforeReadFsMap ;(R3->R0,V)
        BVS     %FT80           ;can't recover new map if both copies broken

        MOV     R0, #"$"
        BL      DoXOS_WriteC
        BVS     %FT70

20                      ;RECURSE DOWN ENTRY POINT
        BL      FindDir         ;(R3->R0,R5,R6,V)
        BVS     %FT70
        SUB     R4, R5, #NewDirEntrySz-DirFirstEntry
        B       %FT35

25
        MOV     R0, #"."
        BL      DoXOS_WriteC
        BVS     %FT70
        BL      TermCommon      ;(R3,R4->R10)

        BL      ReadIndDiscAdd  ;(R3,R4->LR)
        MOV     R2, LR
        BL      ReadIntAtts     ;(R3,R4->LR)
        TSTS    LR, #DirBit
        MOVNE   R3, R2
        BNE     %BT20           ;recurse down if dir
30
 [ fix_5
        BL      ReadIndDiscAdd  ;(R3,R4->LR)
        MOV     R1, LR
        BL      MeasureFileAllocSize_GotMap ;(R1,R3,R4->R0)
        MOVS    R1, R0
 |
        BL      ReadLen         ;(R4->LR)
        MOVS    R1, LR
 ]
        Push    "R5"
        SUB     R5, R4, #DirFirstEntry
        BL      ReturnWholeSpace        ;(R1-R5->R0)
        Pull    "R5"

        MOV     R10,#DeleteChar
        BL      UnTermCommon    ;(R3,R4,R10)
        MOV     R0, #DeleteChar
        BL      DoXOS_WriteC
        BVS     %FT70

35
        LDRB    LR, [R4, #NewDirEntrySz] !
        CMPS    LR, #" "
        BHI     %BT25

        MOV     R7, R3
        BL      ToParent        ;(R3,R6->R3)
        CMPS    R3, R7
        BEQ     %FT45           ;V=0 end when back to root if no match found

        BL      FindDir         ;(R3->R0,R5,R6,V)
        BVS     %FT70

        BL      AgeDir          ;(R7)
        SUB     R4, R5, #NewDirEntrySz-DirFirstEntry
40
        LDRB    LR, [R4, #NewDirEntrySz] !
        BL      ReadIndDiscAdd  ;(R3,R4->LR)
        TEQS    LR, R7
        BNE     %BT40
        MOV     R2, R7
        B       %BT30

45
        MOV     R0, #DeleteChar
        BL      DoXOS_WriteC
        BVS     %FT70
        BL      CritInitReadNewFs       ;(->R10,R11)
        BL      DiscAddToRec            ;(R3->LR)
        MOV     R5, LR
        LDRB    R0, [R5, #Zones]
        B       %FT65

50
        baddr   r0, CMC1        ; Map inconsistent with directory tree
        BL      message_gswrite0
        B       %FT70

55
        BL      InitZoneObj     ;(R0,R10->R8,R9,R11,LR)
        MOV     R1, LR
60
        BL      RdLenLinkBits   ;(R10,R11->R7,R8)
        CMPS    R9, R11
        ADDEQ   R9, R11,R8
        CMPNES  R8, #2
 [ DebugO
 BLS    %FT01
 DREG   r8, "Fragment ID hanging around:"
 DREG   r7, "BitLength:"
 DREG   r0, "In zone:"
 DREG   r11, "At bit offset:"
 DREG   r9, "Next free fragment at bit offset:"
01
 ]
        BHI     %BT50
        ADD     R11,R11,R7
        CMPS    R11,R1
        BLO     %BT60
65
        SUBS    R0, R0, #1
        BPL     %BT55
        BL      UnlockMap
        BL      BeforeReadFsMap ;(R3->R0,V)
        BVS     %FT70
        LDRB    LR, [R5, #DiscFlags]
        TSTS    LR, #AltMapFlag
        baddr   R0, CMC3,EQ             ; Map good
        baddr   R0, CMC2,NE             ; One copy of the map is corrupt. Overwrite it with the good copy (Y/N) ?
        BL      message_gswrite0
        BVS     %FT70
        BEQ     %FT70

        BL      TerseConfirm    ;(V->Z,V)
        BVS     %FT70
        BNE     %FT70
        MOV     R1, #WriteSecsOp :OR: NoEscape
        LDRB    R7, [R5, #SectorSize]
        LDRB    R9, [R5, #Zones]
        BL      MapDiscAdd              ;(R5,R7,R9->R2)
        MOV     R3, R10
        MOV     R4, R9, LSL R7
        BL      RetryDiscOp     ;(R1-R4->R0,R2-R4,V)
        LDRVC   LR, [R5, #DiscFlags]
        BICVC   LR, LR, #AltMapFlag
        STRVC   LR, [R5, #DiscFlags]
70
        BL      UnlockMap
80
        BLVS    FindErrBlock    ;(R0->R0,V)
        BL      FileCoreExit
        Pull    "R7-R11,SB,PC"


; >>>>>>>>>
; DoCompact
; >>>>>>>>>

DoCompact
        Entry  Flag,Dormant  ;leaves SB,LR stacked
        Push    "R7-R11"
        TEQS    R1, #0
        MOV     R1, R0
        BLEQ    IdentifyCurrentDisc     ;(->R0,R3,V) if disc param missing
        MOVNE   R2, #MustBeDisc
        BLNE    FullLookUp              ;(R1,R2->R0-R6,C,V)
        BLVC    BeforeAlterFsMap        ;(R3->R0,V)
        BVS     %FT99
 [ FileCache

  [ WinniesAsFloppies
        BL      DiscWriteBehindWait             ;(R3)
  |
        BL      FloppyDiscWriteBehindWait       ;(R3)
  ]
  [ Module_Version >= 205
        ; Check for drive type based on drive number, not disc number
        MOV     LR, R3, LSR #(32-3)
        DiscRecPtr  LR, LR
        LDRB    LR, [LR, #DiscFlags]
        TST     LR, #FloppyFlag
        LDRB    LR, Interlocks
        Push    "LR"
        LDREQ   R0, WinnieProcessBlk
        LDRNE   R0, FloppyProcessBlk
  |
        LDRB    LR, Winnies
        CMPS    LR, R3, LSR #29
        LDRB    LR, Interlocks
        Push    "LR"
        LDRLO   R0, WinnieProcessBlk
        LDRHS   R0, FloppyProcessBlk
  ]
        BL      ClaimController         ;(R0)
 ]
 [ NewFs
        BL      TestMap         ;(R3->Z)
        BL      DiscAddToRec    ;(R3->LR)
        BNE     %FT03

        LDRB    R0, [LR,#Zones]
        BL      CritInitReadNewFs        ;(->R10,R11)
        SUB     R0, R0, #1
01
        MOV     R1, #8*K
        BL      DefCompactZone  ;(R0,R1,R10->R0,R2,V)
        BVS     %FT02
        SUBS    R0, R0, #1
        BPL     %BT01
02
        BL      UnlockMap
        B       %FT98
03

 |

        BL      DiscAddToRec    ;(R3->LR)
 ]

         ^ 0
LenListPtr      # 4
LenList         # 0
        ASSERT  NewDirEntries>=OldDirEntries
        SUB     SP, SP, #(NewDirEntries+1)*4+LenList    ;space to sort lengths

        LDR     R3, [LR,#RootDir]
        MOV     R7, R3

05
;RECURSE DOWN COMES BACK TO HERE
; R7 disc address of parent dir
; R3 disc address of sub dir to enter

        BL      GetDir          ;(R3->R0,R5,R6,V)
        BVS     %FT95

        Push    "R3"
        BL      ToParent        ;(R3,R6->R3)
        TEQS    R7, R3
        BLNE    InvalidateBufDir
        MOVNE   R3, R7
        BLNE    WriteParent     ;(R3,R6) ensure parent ptr ok for return later
        Pull    "R3"

 [ NewDirEntrySz=OldDirEntrySz   ;init ptr to last sub dir Compacted
        SUB     R6,R5,#NewDirEntrySz-DirFirstEntry
 |
        BL      TestDir      ;(R3->LR)
        SUBEQ   R6, R5, #NewDirEntrySz-DirFirstEntry
        SUBNE   R6, R5, #OldDirEntrySz-DirFirstEntry
 ]
10
        ADD     R1, SP, #LenList        ;init ptr to sort buffer
 [ NewDirEntrySz=OldDirEntrySz
        SUB     R4, R5, #NewDirEntrySz-DirFirstEntry
 |
        BL      TestDir      ;(R3->LR)
        MOVEQ   R11,#NewDirEntrySz
        MOVNE   R11,#OldDirEntrySz
        ADD     R4, R5, #DirFirstEntry
        SUB     R4, R4, R11
 ]
        MOV     R7, #0          ;init dir index
        B       %FT20

15
        CMPS    R6, R4          ;dont consider moving dirs already scanned as
        BLHS    ReadIntAtts     ;parent ptrs to it would not be updated
        TSTHSS  LR, #DirBit
        BHI     %FT18
        BL      ReadLen         ;(R3,R4->LR)
        MOVS    R0, LR
        BLNE    RoundUp         ;(R0,R3->R0) ignore zero length files
        STRNE   R0, [R1]        ;note length
        STRNEB  R7, [R1],#4     ;bottom byte = dir index
18
        ADD     R7, R7, #1
20
 [ NewDirEntrySz=OldDirEntrySz
        LDRB    LR, [R4,#NewDirEntrySz] !
 |
        LDRB    LR, [R4,R11] !
 ]
        CMPS    LR, #" "
        BHI     %BT15

        MOV     LR, #0
        STR     LR, [R1]
        ADD     R0, SP, #LenList
        BL      Sort            ;(R0,R1)
        B       %FT50

25
        STR     R0, [SP,#LenListPtr]
        BIC     R1, LR, #&FF    ;rounded length
        AND     R4, LR, #&FF    ;dir index
 [ NewDirEntrySz=OldDirEntrySz
        ASSERT  NewDirEntrySz=26
        ADD     LR, R4, R4, LSL #1 ;*3
        ADD     R4, R4, LR, LSL #2 ;*13
        ADD     R4, R5, R4, LSL #1
 |
 ?
 ]
        ADD     R4, R4, #DirFirstEntry
        BL      InitReadOldFs   ;(R3->R9,R10,R11)
        BL      ReadIndDiscAdd  ;(R3,R4->LR)
        MOV     R2, LR
        ADD     R0, R1, R2      ;end of file's reserved space
        MOV     R9, #-1         ;init smallest gap bigger than file
30
        BL      NextOldFs       ;(R3,R10,R11->R7,R8,R10,R11,Z)
        BEQ     %FT48           ;files exhausted
        CMPS    R8, R0
        BHS     %FT35           ;gap is after object
        CMPS    R7, R9
        MOVLO   R9, R7
        ADD     LR, R8, R7      ;end of gap
        CMPS    LR, R2
        BEQ     %FT40
        BNE     %BT30

35                  ;if gap joins end of file is there a better gap for file
        ADDEQ   LR, R1, R7      ;(file+gap) length
        CMPEQS  R9, LR
        BHS     %FT48
40                      ;here if file worth moving
        BL      ReturnWholeSpace;(R1,R2,R3->R0,V)
 [ Dev
        mess    VS, "*** ReturnWholeSpace GAVE ERROR TO *Compact ***",NL
 ]
        MOV     R8, R2
        MOV     R10,R1          ;size
        MOV     R11,#fsfile_Create
        BL      ClaimFreeSpace  ;(R3,R10,R11->R0,R2,V)
 [ Dev
        mess    VS,"*** ClaimFreeSpace GAVE ERROR TO *Compact ***",NL
 ]
        Push    "R2-R4"
        MOV     R0, #(1:SHL:UseScratchSpace) :OR: (1:SHL:UseSpareScreen) :OR: (1:SHL:UseWimpFree) :OR: (1:SHL:UseRmaHeap) :OR: (1:SHL:UseSysHeap) :OR: ScatterBit
        MOV     R3, R1          ;size
        MOV     R1, R8          ;source
        BL      MoveData        ;(R0-R3->R0-R3,V)
        Pull    "R2-R4"
        BVS     %FT95
        MOV     R0, R2
        BL      WriteIndDiscAdd ;(R0,R3,R4)

        sbaddr  LR, FirstFcb-FcbNext
        B       %FT42
41                              ;deal with relocating open files
        LDR     R0, [LR,#FcbIndDiscAdd]
        TEQS    R0, R8
        STREQ   R2, [LR,#FcbIndDiscAdd]
        LDR     R0, [LR,#FcbDir]
        TEQS    R0, R8
        STREQ   R2, [LR,#FcbDir]
42
        LDR     LR, [LR,#FcbNext];get next FCB
        TSTS    LR, #ARM_CC_Mask     ;no more FCBs return NE
        BEQ     %BT41

        BL      ReadIntAtts     ;(R3,R4->LR)
        TSTS    LR, #DirBit
        BEQ     %FT48           ;skip if file

        ASSERT  LibDir=UserRootDir+4    ;deal with side effects of moving dir
        ASSERT  CurDir=LibDir+4
        ASSERT  BackDir=CurDir+4
        sbaddr  R0, UserRootDir
        ADD     R1, R0, #BackDir-UserRootDir
43
        LDR     LR, [R0],#4
        TEQS    LR, R8
        STREQ   R2, [R0,#-4]
        CMPS    R0, R1
        BLS     %BT43

        sbaddr  R0, RootCache
        MOV     R1, R0
        B       %FT45
44
        LDR     LR, [R0,#CacheDir]
        TEQS    LR, R8
        STREQ   R2, [R0,#CacheDir]
45
        LDR     R0, [R0,#CacheOlder]
        ADD     R0, SB, R0
        TEQS    R0, R1
        BNE     %BT44

48
        LDR     R0, [SP,#LenListPtr]
50
        LDR     LR, [R0],#4     ;get next entry from sorted length table
        TEQS    LR, #0
        BNE     %BT25

        LDR     LR, BufDir      ;avoid unnecessary writing of map
        CMPS    LR, #-1         ;for new floppy ids
        BL      ClearV
        BLEQ    WriteDirThenFsMap       ;(->R0,V)
        BVS     %FT95
                                ;SEARCH FOR NEXT SUB DIR
 [ NewDirEntrySz=OldDirEntrySz
55
        LDRB    LR, [R6,#NewDirEntrySz] !
 |
        BL      TestDir
        MOVEQ   R0, #NewDirEntrySz
        MOVNE   R0, #OldDirEntrySz
55
        LDRB    LR, [R6,R0] !
 ]
        CMPS    LR, #" "
        BLS     %FT60           ;no more sub dirs
        MOV     R4, R6
        BL      ReadIntAtts     ;(R3,R4->LR)
        TSTS    LR, #DirBit
        BEQ     %BT55           ;loop if file

        BL      ReadIndDiscAdd  ;(R3,R4->LR)
        MOV     R7, R3
        MOV     R3, LR
        B       %BT05           ;recurse down dir

60                              ;dir done, return to parent
        MOV     R7, R3
        BL      TestDir
        ADDEQ   R6, R5, #NewDirSize
        ADDNE   R6, R5, #OldDirSize
        BL      ToParent        ;(R3,R6->R3)
        EORS    R0, R3, R7
        BEQ     %FT90           ;if dir = parent then must be $ so done
        BL      GetDir          ;(R3->R0,R5,R6,V)
        BVS     %FT95
        BL      AgeDir          ;(R7)
 [ NewDirEntrySz=OldDirEntrySz   ;init ptr to last sub dir Compacted
        SUB     R4, R5, #NewDirEntrySz-DirFirstEntry
 |
 ?
 ]

65
 [ NewDirEntrySz=OldDirEntrySz   ;init ptr to last sub dir Compacted
        LDRB    LR, [R4,#NewDirEntrySz] !
 |
 ?
 ]
        BL      ReadIndDiscAdd  ;(R3,R4->LR)
        TEQS    LR, R7
        BNE     %BT65
        MOV     R6, R4
        B       %BT10

90
        BL      SetVOnR0
95
        BL      UnlockMap
        ADD     SP, SP, #LenList+(NewDirEntries+1)*4    ;return temp space
98
 [ FileCache
        Pull    "LR"
        STRB    LR, Interlocks
 ]
99
        BLVS    FindErrBlock    ;(R0->R0,V)
        BL      FileCoreExit
        Pull    "R7-R11,SB,PC"


; ======
; AgeDir
; ======

;entry R7 ind disc address of dir to age

AgeDir
        Push    "R0-R3,R11,LR"
        MOV     R3, R7
        BL      TryCache        ;(R3->R11,V)
        BVS     %FT90
 [ FileCache
        BL      LockDirCache
 ]
        BL      RemoveCacheDir  ;(R11)
                                        ;LINK DIR AS OLDEST
        MOV     R0, #:INDEX:RootCache
        ADD     R1, SB, R0
        LDR     R2, [R1,#CacheYounger]
        ADD     R3, SB, R2
        BL      InvalidateDirCache
        SUB     LR, R11, SB
        STR     R0, [R11,#CacheOlder]
        STR     R2, [R11,#CacheYounger]
        STR     LR, [R1, #CacheYounger]
        STR     LR, [R3, #CacheOlder]
        STR     R11,[R11,#CachePriority]        ;restore non zero priority
        BL      ValidateDirCache

 [ FileCache
        BL      UnlockDirCache
 ]
90
        STRVS   R0, [sp]
        Pull    "R0-R3,R11,PC"


; >>>>>>>>
; DoDefect
; >>>>>>>>

DC0     DCB     "DC0",0
DC1     DCB     "DC1",0
        ALIGN

DoDefect
        Entry   Flag,Dormant  ;leaves SB,LR stacked
        Push    "R7-R11"
        MOV     R1, R0
        MOV     R2, #MustBeDisc
        BL      FullLookUp      ;(R1,R2->R0-R6,V)

 [ Module_Version >= 212
        BLVC    DiscMustBeFileCore
        BVS     %FT81

        Push    "r1"
        MOV     r1, r3, LSR #(32-3)
        BL      CloseAllByDisc          ;(R1->R0,V)
        Pull    "r1"
        BLVC    BeforeAlterFsMap        ;(R3->R0,V)
        BLVC    SkipSpaces
        BLVC    CritInitReadNewFs       ;(->R10,R11)

 [ BigDisc; SBP: Thu 15th December 1994, walked thru and commented.  Found
; that the check for disc address being on disc was incorrect and fixed.
; (was comparing disc addr as sector address against disc size as byte
; address)

; SBP: XOS_ReadUnisgned will only work if defect is within 4G.  Need to
;      do >32bit number handling for big discs.  Also need to watch for
;      above loading of DiscSize.
	MOV	r0, r1                  ; pointer to disc addr string
	BL	ReadHex64               ; (r0->r1,r2)

; check for sector alignment - ie shift right by sectorsize
; then shift left should not change ls word.
	LDRB	LR,[R10,#ZoneHead+SectorSize]
	MOV	R0, R1, LSR LR
	MOV	R0, R0, LSL LR
	CMP	R1, R0
	BEQ	%FT01
	MOV	R0, #BadParmsErr        ; Bad Parameter (how user friendly!)
	BL	SetV
	B	%FT78

01
; check that disc address is on the disc
	LDR	LR, [R10, #ZoneHead+DiscSize]
	SUBS	R0, R1, LR
	LDR	LR, [R10, #ZoneHead+DiscSize2]
	SBCS	R0, R2, LR
	BMI	%FT02                   ; if -ve then OK

	MOV	R0, #BadParmsErr
	BL	SetV
	B	%FT78
02
        LDRB    LR, [R10, #ZoneHead+SectorSize]
	MOV	R0, R1, LSR LR
	RSB	LR, LR, #32
	ORR	R0, R0, R2, LSL LR
 |
        MOVVC   r0, #16                 ; base 16
        ORRVC   r0, r0, #bit31 :OR: bit29 ; terminated and within range
        LDRVC   r2, [r10, #ZoneHead+DiscSize] ; bound above by DiscSize-1
        SUBVC   r2, r2, #1
        BLVC    OnlyXOS_ReadUnsigned      ;(R0-R2->R0-R2,V)
        BVS     %FT78

        ; Check also on a sector boundary
        MOV     R0, R2
        LDRB    R1, [R10,#ZoneHead+SectorSize]
        MOV     LR, R0, LSR R1
        TEQS    R0, LR, LSL R1          ;check disc address at sector boundary
        MOVNE   R0, #BadParmsErr
        BLNE    SetV
        BVS     %FT78
 ]
        BL      DoDefectMapOut
        BVC     %FT78

        ; Don't summarise problem on old map discs
        BL      TestMap
        BNE     %FT78

        ; Start summarising the problem
        B       %FT51

 |
        BVS     %FT81


  [ Module_Version >= 205
        BL      DiscMustBeFileCore ;(R3->V,R0)
        BVS     %FT81
  ]
        BL      TestMap         ;(R3->Z)
        MOVNE   R0, #DefectErr
        BLNE    SetV
        Push    "R1"
        MOVVC   R1, #8
        BLVC    CloseAllByDisc  ;(R1->R0,V)
        Pull    "R1"
        BLVC    BeforeAlterFsMap        ;(R3->R0,V)
        BVS     %FT81

        BL      SkipSpaces              ;(R1->R0,R1,C)
        BL      CritInitReadNewFs       ;(->R10,R11)
        MOV     R0, #16
        ORR     R0, R0, #bit31 :OR: bit29
        LDR     R2, [R10,#ZoneHead+DiscSize]
        SUB     R2, R2, #1
        BL      OnlyXOS_ReadUnsigned      ;(R0-R2->R0-R2,V)
        BVS     %FT78
        MOV     R0, R2
        LDRB    R1, [R10,#ZoneHead+SectorSize]
        MOV     LR, R0, LSR R1
        TEQS    R0, LR, LSL R1          ;check disc address at sector boundary
        MOVNE   R0, #BadParmsErr
        BLNE    SetV
        BNE     %FT78
        Push    "R0,R3"

        BL      DiscAddToMapPtr         ;(R0,R10->R11,LR)
        MOV     R1, R11
        MOV     R0, LR

        BL      InitZoneObj     ;(R0,R10->R8,R9,R11,LR)
        MOV     R5, LR
        TEQS    R9, R8
        MOVEQ   R9, #0
        MOV     R0, #bit31      ;rogue previous fragment
        B       %FT12

06
        TEQS    R11,R9
        BNE     %FT09
        BL      RdLinkBits      ;(R10,R11->R8,Z)
        MOVEQ   R9, #0
        ADDNE   R9, R11,R8
        MOV     R8, R11
09
        MOV     R0, R11
        MOV     R11,R4
12
        BL      RdLenBits       ;(R10,R11->R7)
        ADD     R4, R11,R7
        CMPS    R4, R1
        BLS     %BT06           ;loop if not reached defect fragment

        TEQS    R11,R9
        BNE     %FT51           ;defect not in a free space

        Push    "R8,R9"
        BL      RdLinkBits      ;(R10,R11->R8,Z)
        MOVEQ   R9, #0
        ADDNE   R9, R11,R8
        STR     R9, [SP, #4]
        MOV     R3, R11
        BL      AllocBitWidth   ;(R10->LR)
        MOV     R9, LR
        SUB     LR, LR, #1
        BIC     R1, R1, LR      ;round defect down to start of allocation unit
        ADD     R6, R1, R9      ;earliest possible defect end
        BL      MinMapObj       ;(R10->LR)
        MOV     R2, LR

        ; Registers here:
        ; R0 = previous fragment start - top bit set if none
        ; R1 = Defect start at allocation unit boundary
        ; R2 = MinMapObj
        ; R3 = Start of free object bad block was found in
        ; R4 = Start of fragment after free fragment containing bad block
        ; R5 = end of fragment list
        ; R6 = Earliest end of defect object (based on allocation width)

15
        SUB     LR, R1, R3      ; Space before defect
        CMPS    LR, R2
        BHS     %FT18           ; Branch if enough gap before defect for a whole object

        ; Not enough room before defect to fit an object
        MOV     R1, R3
        MOVS    R11,R0
        BLPL    RdLenLinkBits   ;(R10,R11->R7,R8)
        TEQPLS  R8, #1
        MOVEQ   R1, R0          ; EQ if previous object is a bad block object, ie
                                ; if there's no room for free space before the defect
                                ; and the previous object is a bad block then stretch
                                ; that to cover the defect

18
        SUB     LR, R4, R6      ; Space after defect
        CMPS    LR, R2
        CMPLOS  R4, R5
        BHS     %FT21           ; Branch if either there's room for an object after the defect
                                ; or there isn't an object after the free fragment containing the defect

        ; There isn't room after the defect for an object and there's an object after
        ; the free fragment containing the defect
        MOV     R6, R4
        MOV     R11,R4
        BL      RdLenLinkBits   ;(R10,R11->R7,R8)
        TEQS    R8, #1
        ADDEQ   R6, R4, R7      ; Object after defect is a bad block - stretch it down over the defect

21
        ; Now check defect fragment is big enough
        SUB     LR, R6, R1
        CMPS    LR, R2
        BHS     %FT24

        ; Defect fragment isn't big enough, so stretch defect
        ; fragment up if possible, else stretch it down and try again...
        CMPS    R6, R4
        ADDLO   R6, R6, R9
        SUBHS   R1, R1, R9
        B       %BT15

24
        Pull    "R8,R9"

        ; Write the defect fragment
        MOV     R0, #1
        BL      WrLinkBits      ;(R0,R1,R10)
        SUB     R0, R6, R1
        BL      WrLenBits       ;(R0,R1,R10)

        ; next free fragment
        SUBS    R7, R1, R3
        MOV     R1, R8
        MOVHI   R0, R3
        BLHI    WrFreeNext      ;(R0,R1,R10)
        MOVHI   R0, R7
        MOVHI   R1, R3
        BLHI    WrLenBits       ;(R0,R1,R10)

        ; previous free fragment
        CMPS    R4, R6
        MOVHI   R0, R6
        BLHI    WrFreeNext      ;(R0,R1,R10)
        SUBHI   R0, R4, R6
        MOVHI   R1, R6
        BLHI    WrLenBits       ;(R0,R1,R10)

        ; previous previous free fragment
        MOV     R0, R9
        BL      WrFreeNext      ;(R0,R1,R10)

        ; Write the whole lot out
        Pull    "R2,R3"
        BL      WriteFsMap      ;(->R0,V)
        BVS     %FT78

27
        ; Now update the bad block list (if present)

 [ Module_Version >= 205
        ; Base presence of defect list on presence of defect list
        ; (These checks _ASSUME_ disc is in a drive)
        MOV     LR, R3, LSR #(32-3)
        DiscRecPtr LR, LR
        LDRB    LR, [LR, #DiscsDrv]
        DrvRecPtr LR, LR
        LDRB    LR, [LR, #DrvFlags]
        TST     LR, #HasDefectList
        BEQ     %FT78

        MOV     LR, R3, LSR #(32-3)
        DiscRecPtr LR, LR
        LDRB    LR, [LR, #DiscsDrv]
 |
  [ fix_1
  ! 0,"fix 1"
        LDRB    LR, Winnies
  |
        LDR     LR, Winnies
  ]
        CMPS    LR, R3, LSR #29
        BLS     %FT78           ;no defect list to update if floppy, V=0

        MOV     LR, R3, LSR #29
 ]
        LDR     R0, DefectSpace
        ADD     R0, SB, R0
        ASSERT  SzDefectList = 1 :SHL: 9
        ADD     R0, R0, LR, LSL #9

        SUB     R1, R0, #4
30
        LDR     LR, [R1, #4]!
        CMPS    LR, R2
        BLO     %BT30
        BEQ     %FT78           ;defect already in list

        MOV     R4, R1
33
        TSTS    LR, #DiscBits
        LDREQ   LR, [R4, #4]!
        BEQ     %BT33

        LDR     LR, [R4, #4]!
        TEQS    LR, #0
        BNE     %FT78           ;defect list full

36
        LDR     LR, [R4, #-4]!  ;move up defect list
        STR     LR, [R4, #4]
        CMPS    R4, R1
        BHI     %BT36
        STR     R2, [R1]

        MOV     R4, R0
        MOV     R1, #0
39
        LDR     LR, [R4], #4
        TSTS    LR, #DiscBits
        EOREQ   R1, LR, R1, ROR #13
        BEQ     %BT39
        EOR     R1, R1, R1, LSR #16
        EOR     R1, R1, R1, LSR #8
        STRB    R1, [R4, #-4]

        MOV     R1, #SzDefectList
        BL      CheckSum        ;(R0,R1->R0-R2,V)
        SUB     R1, R1, #1
        STRB    R2, [R0, R1]
        MOV     R1, #WriteSecsOp :OR: NoEscape
        AND     R2, R3, #DiscBits
        ADD     R2, R2, #DefectListDiscAdd
        MOV     R3, R0
        MOV     R4, #SzDefectList
        BL      DoDiscOp        ;(R1-R4->R0,R2-R4,V)
        B       %FT78
 ]


TermCommon
42
        MOV     R10,#0
UnTermCommon
45
        Push    "R0,R2,R11,LR"  ;Print out a name from a dir (R3,R4,R10)
        ADD     R2, R4, #DirObName
        MOV     R11,#NameLen
48
        LDRB    LR, [R2], #1
        MOVS    R0, R10
        MOVEQ   R0, LR
        CMPS    LR, #DeleteChar
        CMPNES  LR, #" "
        BLHI    DoXOS_WriteC
        ADDVS   SP, SP, #4*4
        BVS     %FT78
        SUBHIS  R11,R11,#1
        BHI     %BT48
        Pull    "R0,R2,R11,PC",,^

51
 [ Module_Version >= 212
 |
        Pull    "R2,R3"
        BL      RdLinkBits      ;(R10,R11->R8,Z)
        TEQS    R8, #1
        BEQ     %BT27
 ]

        CMPS    R8, #2          ;V=0
        MOVEQ   R0, #DefectErr
        BLEQ    SetV

 [ DebugQ
        DREG    r3, "Entering dir tree scan on root ",cc
        DREG    r2, " and defect "
 ]

        MOVVC   R0, #"$"
        BLVC    DoXOS_WriteC
        BVS     %FT78

        MOV     R9, #0          ;clear found flag
        MOV     R11,R2          ;defect disc add

54                      ;RECURSE DOWN ENTRY POINT
        BL      FindDir         ;(R3->R0,R5,R6,V)
        BVS     %FT78
        SUB     R4, R5, #NewDirEntrySz-DirFirstEntry
        B       %FT72

57
        BL      ReadIntAtts     ;(R3,R4->LR)
        ANDS    R7, LR, #DirBit
        BEQ     %FT60
        TEQS    R9, #0
        BNE     %FT72
        MOV     R0, #"."
        BL      DoXOS_WriteC
        BLVC    %BT42           ;(R3,R4->R10)
        BVS     %FT78

60
        MOV     R5, R9
        BL      ReadIndDiscAdd  ;(R3,R4->LR)
        MOV     R1, LR
        BIC     R0, LR, #DiscBits
        TEQS    R8, R0, LSR #8
        BNE     %FT69

        CMPS    R7, #0          ;V=0
        MOVEQ   R0, #"."
        BLEQ    DoXOS_WriteC
        BVS     %FT78
        BLEQ    %BT42           ;(R3,R4->R10) print out filename
        Push    "R4,R5"
        BL      ReadLen         ;(R4->LR)
        MOV     R0, LR
        MOV     R5, #0
        MOV     R9, #-1         ;init pre gap map ptr, also match found flag
63
        MOV     R2, R1
        BL      FindFileFragment        ;(R2,R5,R9->R2,R4,R9,LR)
        CMPS    R4, R0
        MOVHI   R4, R0
        BIC     R2, R2, #DiscBits
        ADD     LR, R2, R4
        SUBS    R2, R11,R2
        CMPHS   LR, R11
        BHI     %FT66           ;defect inside file
        ADD     R5, R5, R4
        SUBS    R0, R0, R4
        BHI     %BT63

        Pull    "R4,R5"
        baddr   r0, DC0         ;  must be moved
        BL      message_gswrite0
        BVC     %FT69
        BVS     %FT78

66
        ADD     R0, R5, R2
        Pull    "R4,R5"

        SUB     SP, SP, #12
        MOV     R1, SP
        MOV     R2, #12
        BL      OnlyXOS_ConvertHex8     ;(R0-R2->R0-R2)
67
        LDRB    LR, [R0], #1
        CMPS    LR, #"0"+1
        CMPLOS  R0, R1
        BLO     %BT67
        SUB     R0, R0, #1
        MOV     r4, r0
        baddr   r0, DC1         ;  has defect at offset %0
        BL      message_gswrite01
        ADD     SP, SP, #12
        BVS     %FT78
        CMPS    R7, #0
        BNE     %FT78           ;V=0 don't try to enter dir with defect

69
        TEQS    R7, #DirBit     ;IF  DIR
        TEQEQS  R5, #0          ;AND NO MATCH BEFORE THIS DIR
        MOVEQ   R3, R1
        BEQ     %BT54           ;THEN RECURSE DOWN

72
        LDRB    LR, [R4, #NewDirEntrySz] !
        CMPS    LR, #" "
        BHI     %BT57

        TEQS    R9, #0
        BNE     %FT78           ;V=0 don't return to parent once match found

        MOV     R7, R3
        BL      ToParent        ;(R3,R6->R3)
        CMPS    R3, R7
        BEQ     %FT78           ;V=0 end when back to root if no match found

        BL      FindDir         ;(R3->R0,R5,R6,V)
        BVS     %FT78

        BL      AgeDir          ;(R7)
        SUB     R4, R5, #NewDirEntrySz-DirFirstEntry
75
        LDRB    LR, [R4, #NewDirEntrySz] !
        BL      ReadIndDiscAdd  ;(R3,R4->LR)
        TEQS    LR, R7
        BNE     %BT75
        MOV     R10,#DeleteChar
        BL      %BT45           ;(R3,R4,R10)
        MOV     R0, #DeleteChar
        BL      DoXOS_WriteC
        BVC     %BT72

78
        BL      UnlockMap
81
        BLVS    FindErrBlock    ;(R0->R0,V)
        BL      FileCoreExit
        Pull    "R7-R11,SB,PC"

 [ Module_Version >= 212
; ==============
; DoDefectMapOut
; ==============

; entry:
;       r0 = disc address to be mapped out
;       r3 = top 3 bits disc number
;       Map for disc must be BeforeAlterFsMapped

; exit:
;       V, r0=error possible
;       r8 = extra info on error (in particular the obj Id containing the defect)

DoDefectMapOut ROUT
        Push    "R0-R11,LR"

 [ DebugQ
        DREG    r0,"DoDefectMapOut(",cc
        DREG    r3,",",cc
        DLINE   ")"
 ]

        ; Can't map out defects on old maps - tough
        BL      TestMap         ;(R3->Z)
        MOVNE   R0, #DefectErr
        BLNE    SetV
 [ DebugQ
        BVC     %FT01
        DLINE   "Wrong sort of map"
01
 ]
        BVS     %FT81

        ; Get the parameters for this map
        BL      CritInitReadNewFs       ;(->R10,R11)

        ; Find the map ptr and zone for the defect
        LDR     r0, [sp, #0*4]
        BL      DiscAddToMapPtr         ;(R0,R10->R11,LR)
        MOV     R1, R11
        MOV     R0, LR

        ; Start wandering through that zone
        BL      InitZoneObj     ;(R0,R10->R8,R9,R11,LR)
        MOV     R5, LR
        TEQS    R9, R8
        MOVEQ   R9, #0
        MOV     R0, #bit31      ;rogue previous fragment
        B       %FT12

06
        TEQS    R11,R9
        BNE     %FT09
        BL      RdLinkBits      ;(R10,R11->R8,Z)
        MOVEQ   R9, #0
        ADDNE   R9, R11,R8
        MOV     R8, R11
09
        MOV     R0, R11
        MOV     R11,R4
12
        BL      RdLenBits       ;(R10,R11->R7)
        ADD     R4, R11,R7
        CMPS    R4, R1
        BLS     %BT06           ;loop if not reached defect fragment

        TEQS    R11,R9
        BNE     %FT51           ;defect not in a free space

        Push    "R8,R9"
        BL      RdLinkBits      ;(R10,R11->R8,Z)
        MOVEQ   R9, #0
        ADDNE   R9, R11,R8
        STR     R9, [SP, #4]
        MOV     R3, R11
        BL      AllocBitWidth   ;(R10->LR)
        MOV     R9, LR
        SUB     LR, LR, #1
        BIC     R1, R1, LR      ;round defect down to start of allocation unit
        ADD     R6, R1, R9      ;earliest possible defect end
        BL      MinMapObj       ;(R10->LR)
        MOV     R2, LR

        ; Registers here:
        ; R0 = previous fragment start - top bit set if none
        ; R1 = Defect start at allocation unit boundary
        ; R2 = MinMapObj
        ; R3 = Start of free object bad block was found in
        ; R4 = Start of fragment after free fragment containing bad block
        ; R5 = end of fragment list
        ; R6 = Earliest end of defect object (based on allocation width)

15
 [ DebugQ
        DREG    r1,"Trying defect from ",cc
        DREG    r6," to "
 ]
        SUB     LR, R1, R3      ; Space before defect
        CMPS    LR, R2
        BHS     %FT18           ; Branch if enough gap before defect for a whole object

        ; Not enough room before defect to fit an object
        MOV     R1, R3
        MOVS    R11,R0
        BLPL    RdLenLinkBits   ;(R10,R11->R7,R8)
        TEQPLS  R8, #1
        MOVEQ   R1, R0          ; EQ if previous object is a bad block object, ie
                                ; if there's no room for free space before the defect
                                ; and the previous object is a bad block then stretch
                                ; that to cover the defect

18
        SUB     LR, R4, R6      ; Space after defect
        CMPS    LR, R2
        BHS     %FT21           ; Branch if there's still room for another fragment

        ; There isn't room after the defect for an object and there's an object after
        ; the free fragment containing the defect
        MOV     R6, R4
        MOV     R11,R4

        ; Branch if there's not another fragment after this free fragment
        CMP     R4, R5
        BHS     %FT21

        ; If there is another fragment, is it a bad block fragment?
        BL      RdLenLinkBits   ;(R10,R11->R7,R8)
        TEQS    R8, #1
        ADDEQ   R6, R4, R7      ; Object after defect is a bad block - stretch it down over the defect

21
        ; Now check defect fragment is big enough
        SUB     LR, R6, R1
        CMPS    LR, R2
        BHS     %FT24

        ; Defect fragment isn't big enough, so stretch defect
        ; fragment up if possible, else stretch it down and try again...
        CMPS    R6, R4
        ADDLO   R6, R6, R9
        SUBHS   R1, R1, R9
        B       %BT15

24
        Pull    "R8,R9"

        ; Write the defect fragment
        MOV     R0, #1
        BL      WrLinkBits      ;(R0,R1,R10)
        SUB     R0, R6, R1
 [ DebugQ
        DREG    R0, "Writing defect block length of "
 ]
        BL      WrLenBits       ;(R0,R1,R10)

        ; next free fragment
        SUBS    R7, R1, R3
        MOV     R1, R8
        MOVHI   R0, R3
 [ DebugQ
        BLS     %FT01
        DREG    R0, "(a)Writing freelink to ",cc
        DREG    R1, " at "
01
 ]
        BLHI    WrFreeNext      ;(R0,R1,R10)
        MOVHI   R0, R7
        MOVHI   R1, R3
 [ DebugQ
        BLS     %FT01
        DREG    R0, "(b)Writing length of ",cc
        DREG    R1, " at "
01
 ]
        BLHI    WrLenBits       ;(R0,R1,R10)

        ; previous free fragment
        CMPS    R4, R6
        MOVHI   R0, R6
 [ DebugQ
        BLS     %FT01
        DREG    R0, "(c)Writing freelink to ",cc
        DREG    R1, " at "
01
 ]
        BLHI    WrFreeNext      ;(R0,R1,R10)
        SUBHI   R0, R4, R6
        MOVHI   R1, R6
 [ DebugQ
        BLS     %FT01
        DREG    R0, "(d)Writing length of ",cc
        DREG    R1, " at "
01
 ]
        BLHI    WrLenBits       ;(R0,R1,R10)

        ; previous previous free fragment
        MOV     R0, R9
 [ DebugQ
        DREG    R0, "(e)Writing freelink to ",cc
        DREG    R1, " at "
 ]
        BL      WrFreeNext      ;(R0,R1,R10)

        ; Write the whole lot out
 [ DebugQ
        DLINE   "Writing out the FsMap"
 ]
        BL      WriteFsMap      ;(->R0,V)
 [ DebugQ
        DLINE   "FsMap now written out"
 ]
        BVS     %FT78

27
        ; Now update the bad block list (if present)

        ; Pick up bad block's address
        LDR     r2, [sp, #0*4]          ; r0in

        ; Base presence of defect list on presence of defect list
        LDR     r3, [sp, #3*4]
        MOV     LR, R3, LSR #(32-3)
        DiscRecPtr LR, LR
        LDRB    LR, [LR, #DiscsDrv]
        DrvRecPtr LR, LR
        LDRB    LR, [LR, #DrvFlags]
        TST     LR, #HasDefectList
        BEQ     %FT78                   ; No defect list - sad

 [ BigDisc ;SBP: Thu 15th December 1994 - walked thru, looks OK
	BL      UpdateBadBlockList      ; UpdateBadBlockList now sep. routine
	B	%FT78
51
        ; Defect found in non-free block - has it already been mapped out?
        BL      RdLinkBits      ;(R10,R11->R8,Z)
        TEQS    R8, #1
        BEQ     %BT27           ; Yes, already mapped out

 [ DebugQ
        DLINE   "Not in free space"
 ]

        MOV     r0, #DefectErr
        BL      SetV
        STR     r8, [sp, #8*4]
78
81
 [ DebugQ
        DLINE   "Defect map-out attempt complete"
 ]
        STRVS   r0, [sp, #0*4]
        Pull    "R0-R11,PC"

 |

 [ DebugQ
        DLINE   "Updating the bad block list"
 ]

        MOV     LR, R3, LSR #(32-3)
        DiscRecPtr LR, LR
        LDRB    LR, [LR, #DiscsDrv]
        LDR     R0, DefectSpace
        ADD     R0, SB, R0
        ASSERT  SzDefectList = 1 :SHL: 9
        ADD     R0, R0, LR, LSL #9

        SUB     R1, R0, #4
30
        LDR     LR, [R1, #4]!
        CMPS    LR, R2
        BLO     %BT30

 [ DebugQ
        BNE     %FT01
        DLINE   "Defect already in list"
01
 ]
        BEQ     %FT78           ;defect already in list

        MOV     R4, R1
33
        TSTS    LR, #DiscBits
        LDREQ   LR, [R4, #4]!
        BEQ     %BT33

        LDR     LR, [R4, #4]!
        TEQS    LR, #0
 [ DebugQ
        BEQ     %FT01
        DLINE   "Defect list full"
01
 ]
        BNE     %FT78           ;defect list full

36
        LDR     LR, [R4, #-4]!  ;move up defect list
        STR     LR, [R4, #4]
        CMPS    R4, R1
        BHI     %BT36
        STR     R2, [R1]

        MOV     R4, R0
        MOV     R1, #0
39
        LDR     LR, [R4], #4
        TSTS    LR, #DiscBits
        EOREQ   R1, LR, R1, ROR #13
        BEQ     %BT39
        EOR     R1, R1, R1, LSR #16
        EOR     R1, R1, R1, LSR #8
        STRB    R1, [R4, #-4]

        MOV     R1, #SzDefectList
        BL      CheckSum        ;(R0,R1->R0-R2,V)
        SUB     R1, R1, #1
        STRB    R2, [R0, R1]
        MOV     R1, #WriteSecsOp :OR: NoEscape
        AND     R2, R3, #DiscBits
        ADD     R2, R2, #DefectListDiscAdd
        MOV     R3, R0
        MOV     R4, #SzDefectList
        BL      DoDiscOp        ;(R1-R4->R0,R2-R4,V)
 [ DebugQ
        DLINE   "Bad block list now written out"
 ]
        B       %FT78

51
        ; Defect found in non-free block - has it already been mapped out?
        BL      RdLinkBits      ;(R10,R11->R8,Z)
        TEQS    R8, #1
        BEQ     %BT27           ; Yes, already mapped out

 [ DebugQ
        DLINE   "Not in free space"
 ]

        MOV     r0, #DefectErr
        BL      SetV
        STR     r8, [sp, #8*4]

78

81
 [ DebugQ
        DLINE   "Defect map-out attempt complete"
 ]
        STRVS   r0, [sp, #0*4]
        Pull    "R0-R11,PC"

 ] ; BigDisc

 ] ; Version>=212

 [ BigDisc

; ==================
; UpdateBadBlockList
; ==================

; entry:
;       r2 = disc address to be mapped out
;       r3 = top 3 bits disc number
;       Map for disc must be BeforeAlterFsMapped

; exit:
;       V, r0=error possible

UpdateBadBlockList ROUT

 [ DebugQ
        DLINE   "Updating the bad block list"
 ]

 ; keep disc record pointer in R5

        MOV     LR, R3, LSR #(32-3)
        DiscRecPtr R5, LR
        LDRB    LR, [R5, #DiscsDrv]
        LDR     R0, DefectSpace
        ADD     R0, SB, R0
        ASSERT  SzDefectList = 1 :SHL: 9
        ADD     R0, R0, LR, LSL #9

	MOV	R4, #512*1024*1024	; 512 meg
	LDRB	LR, [R5, #SectorSize]	; get sector size
	MOV	R4, R4, LSR LR
	CMP	R2, R4			; is the defect in the first or second list?
	BHS	%FT50			; in second defect list

; in first list.  shift left to get byte address

	MOV	R2, R2, LSL LR

        SUB     R1, R0, #4
30
        LDR     LR, [R1, #4]!
        CMPS    LR, R2
        BLO     %BT30

 [ DebugQ
        BNE     %FT01
        DLINE   "Defect already in list"
01
 ]
        BEQ     %FT81           ;defect already in list

        MOV     R4, R1
33
        TSTS    LR, #DiscBits
        LDREQ   LR, [R4, #4]!
        BEQ     %BT33

; found end of first list - is there a second list?

 [ UseBigFlag
        ; use BigFlag field for test
        LDRB    LR, [R5,#BigFlag]
        TSTS    LR, #1
        BNE     %FT40
 |
        ; use size of disc for test
	LDR	LR, [R5, #DiscSize2]
	CMPS	LR, #0
	BNE	%FT40
	LDR	LR, [R5, #DiscSize]
	TSTS	LR, #DiscBits
	BNE	%FT40
 ]

; no second defect list, use normal code

35
        LDR     LR, [R4, #4]!
        TEQS    LR, #0
 [ DebugQ
        BEQ     %FT01
        DLINE   "Defect list full"
01
 ]
        BNE     %FT81           ;defect list full

36
        LDR     LR, [R4, #-4]!  ;move up defect list
        STR     LR, [R4, #4]
        CMPS    R4, R1
        BHI     %BT36
        STR     R2, [R1]

37
        MOV     R4, R0
        MOV     R1, #0
39
        LDR     LR, [R4], #4
        TSTS    LR, #DiscBits
        EOREQ   R1, LR, R1, ROR #13
        BEQ     %BT39
        EOR     R1, R1, R1, LSR #16
        EOR     R1, R1, R1, LSR #8
        STRB    R1, [R4, #-4]

        MOV     R1, #SzDefectList
        BL      CheckSum        ;(R0,R1->R0-R2,V)
        SUB     R1, R1, #1
        STRB    R2, [R0, R1]

; generate disc address
	LDRB	R1, [R5, #SectorSize]
	MOV	LR, #DefectListDiscAdd
        AND     R2, R3, #DiscBits
        ADD     R2, R2, LR, LSR R1

        MOV     R3, R0
        MOV     R4, #SzDefectList
        MOV     R1, #WriteSecsOp :OR: NoEscape
        BL      DoDiscOp        ;(R1-R4->R0,R2-R4,V)
 [ DebugQ
        DLINE   "Bad block list now written out"
 ]
        B       %FT81

40

; second defect list present.  Have to find its end too, and bump it up if need be

        MOV     R6, R4
	LDR	LR, [R6, #4]!
43
        TSTS    LR, #DiscBits
        LDREQ   LR, [R6, #4]!
        BEQ     %BT43

45
        LDR     LR, [R6, #4]!
        TEQS    LR, #0
 [ DebugQ
        BEQ     %FT01
        DLINE   "Defect list full"
01
 ]
        BNE     %FT81           ;defect list full

46
        LDR     LR, [R6, #-4]!  ;move up defect list
        STR     LR, [R6, #4]
        CMPS    R6, R1
        BHI     %BT46
        STR     R2, [R1]

	B	%BT37		;use original code to checksum list

50
; here the defect is in the second defect list.  Move to this list,
; and use similar code to that above to adjust the list, then
; jump back to 37 again to checksum.

 [ UseBigFlag
        ; for safety, check if second defect list actually present
        ; if not there then do nothing.  (Could be unix disc)
        LDRB    LR, [R5, #BigFlag]
        TSTS	LR, #1
	CLRV	; this is not an error condition
	BEQ	%FT81
 ]

; first, find end of the first defect list

	MOV	R6, R0
51
	LDR	LR, [R6], #4
	TSTS	LR, #DiscBits
	BEQ	%BT51

; R6 now points to start of 2nd defect list

        SUB     R1, R6, #4
52
        LDR     LR, [R1, #4]!
        CMPS    LR, R2
        BLO     %BT52

 [ DebugQ
        BNE     %FT01
        DLINE   "Defect already in list"
01
 ]
        BEQ     %FT81           ;defect already in list

        MOV     R4, R1
53
        TSTS    LR, #DiscBits
        LDREQ   LR, [R4, #4]!
        BEQ     %BT53

        LDR     LR, [R4, #4]!
        TEQS    LR, #0
 [ DebugQ
        BEQ     %FT01
        DLINE   "Defect list full"
01
 ]
        BNE     %FT81           ;defect list full

56
        LDR     LR, [R4, #-4]!  ;move up defect list
        STR     LR, [R4, #4]
        CMPS    R4, R1
        BHI     %BT56
        STR     R2, [R1]

        MOV     R4, R6
        MOV     R1, #0
59
        LDR     LR, [R4], #4
        TSTS    LR, #DiscBits
        EOREQ   R1, LR, R1, ROR #13
        BEQ     %BT39
        EOR     R1, R1, R1, LSR #16
        EOR     R1, R1, R1, LSR #8
        STRB    R1, [R4, #-4]

        MOV     R1, #SzDefectList
        BL      CheckSum        ;(R0,R1->R0-R2,V)
        SUB     R1, R1, #1
        STRB    R2, [R0, R1]

; generate disc address (sector address)
	LDRB	R1, [R5, #SectorSize]
	MOV	LR, #DefectListDiscAdd
        AND     R2, R3, #DiscBits
        ADD     R2, R2, LR, LSR R1

        MOV     R3, R0
        MOV     R4, #SzDefectList
        MOV     R1, #WriteSecsOp :OR: NoEscape
        BL      DoDiscOp        ;(R1-R4->R0,R2-R4,V)
 [ DebugQ
        DLINE   "Bad block list now written out"
 ]
        B       %FT81
81
 [ DebugQ
        DLINE   "Defect map-out attempt complete"
 ]
        STRVS   r0, [sp, #0*4]
        Pull    "R0-R11,PC"
 ]

; >>>>>>>>>>
; DoDismount
; >>>>>>>>>>

DoDismount ROUT
        Entry  Flag,Dormant         ;leaves SB,LR stacked
        Push    "R0"
 [ DebugL
 DSTRING r0, "Dismount on "
 ]
        TEQS    R1, #0
        BNE     %FT20

        BL      IdentifyCurrentDisc     ;(->R0,R3,V) If no param dismount current disc
10
        MOVVC   R1, R3, LSR #(32-3)
        BLVC    ActiveDismountDisc      ;(R1->R0,V)
        B       %FT95

20
        MOV     R1, R0                  ;string ptr
        MOV     R2, #MustBeDisc
        BLNE    FullLookUp              ;(R1,R2->R0-R6,V)
        BVC     %BT10                   ;If disc name parsed ok then dismount it

        TEQS    R0, #AmbigDiscErr
        BNE     %FT50

        MOV     R2, #0          ;clear error flag
        MOV     R3, #0
        sbaddr  R4, DiscRecs+DiscName
30
        LDRB    LR, [R4,#Priority-DiscName]
        TEQS    LR, #0
        BEQ     %FT40           ;unused disc rec
        BL      TestDir         ;(R3->LR,Z)
        MOVEQ   R5, #&FF        ;set up bit 7 chars mask
        MOVNE   R5, #&7F
        BL      LexEqv          ;(R1,R4,R5->LO/EQ/HI)
        BNE     %FT40           ;mismatch

        Push    "R1"
        MOV     R1, R3, LSR #(32-3)
        BL      ActiveDismountDisc ;(R1->R0,V)
        MOVVS   R2, R0
        Pull    "R1"

40
        ADD     R4, R4, #SzDiscRec
        ADDS    R3, R3, #1 :SHL: (32-3) ;inc disc num bits
        BCC     %BT30                   ;loop for next disc rec

        B       %FT60

50
        MOV     R2, R0
        LDR     R1, [SP]
        BL      ParseDrive              ;(R1->R0,V)
        BLVC    DriveContentsUnknown    ;(R0)
60
        MOV     R0, R2
        BL      SetVOnR0
95
        BL      FileCoreExit
        BLVS    FindErrBlock            ;(R0->R0,V)
        Pull    "R1,SB,PC"


; ====================
; DriveContentsUnknown
; ====================

; force Drive contents unknown
;
; entry r0 = drive

DriveContentsUnknown
        Push    "r0,lr"
 [ Debug4 :LOR: DebugL
        DREG    r0, "DriveContentsUnknown(",cc
        DLINE   ")"
 ]
        BL      UnlinkByDrive   ;(R0)
        DrvRecPtr r0, r0
        MOV     lr, #Uncertain :OR: Unknown
        STRB    lr, [r0, #DrvsDisc]
        LDRB    lr, [r0, #DrvFlags]
        BIC     lr, lr, #LastDiscOpWasFormat
        STRB    lr, [r0, #DrvFlags]
 [ DebugL
        DLINE   "LastDiscOpWasFormat clear (C)"
 ]
        Pull    "r0,pc",,^


; ==================
; ActiveDismountDisc
; ==================

; entry R1 = disc
; exit If error V set, R0 error

; As DismountDisc, but this dismount is triggered by the user actively dismounting
; rather than the dismount happening behind the user's back. The main difference
; being that ActiveDismountDisc sends a Service_DismountDisc.

ActiveDismountDisc ROUT
        Push    "r1,r2,r3,r11,lr"
        MOV     r11,sp

        ; Calculate length needed for a suitable stack frame and grab that
        LDR     r1, FS_Title
        BL      strlen
        ADD     r3, r3, #2+NameLen+1+3  ; 2 for ::, NameLen for disc title, 1 for terminator, 3 for round-up
        BIC     r3, r3, #3
        SUB     sp, sp, r3

        ; Copy FS_Title
        MOV     r2, sp
10
        LDRB    lr, [r1], #1
        CMP     lr, #" "
        STRHIB  lr, [r2], #1
        BHI     %BT10

        ; Copy ::
        MOV     lr, #":"
        STRB    lr, [r2], #1
        STRB    lr, [r2], #1

        ; Generate disc name or drive number as appropriate
        LDR     r1, [r11, #0*4]
        DiscRecPtr r3, r1
        ADD     r3, r3, #DiscName
        LDRB    lr, [r3], #1
        CMP     lr, #" "
        BLS     %FT30

        MOV     r1, #NameLen

20
        STRB    lr, [r2], #1
        LDRB    lr, [r3], #1
        CMP     lr, #" "
        SUBHIS  r1, r1, #1
        BHI     %BT20

        B       %FT40

30
        LDRB    lr, [r3, #DiscsDrv - DiscName - 1]
        EOR     lr, lr, #4              ; Convert to external numbering
        ADD     lr, lr, #"0"
        STRB    lr, [r2], #1

40
        ; Terminate the string
        MOV     lr, #0
        STRB    lr, [r2], #1

        ; Do the service
        MOV     r1, #Service_DiscDismounted
        MOV     r2, sp
 [ DebugL
        DREG    r1, "Issuing service ",cc
        DSTRING r2, " with r2="
 ]
        BL      DoXOS_ServiceCall
        LDRVC   r1, [r11, #0*4]         ; r1 in
        BLVC    DismountDisc

        MOV     sp, r11
        Pull    "r1,r2,r3,r11,pc"

; ============
; DismountDisc
; ============

; entry R1 = disc
; exit If error V set, R0 result

DismountDisc
 [ Module_Version >= 205
        Push    "R0-R7,LR"
 |
        Push    "R0-R6,LR"
 ]

        ; Hold the disc in R6
        MOV     R6,R1

        ; Check disc in use
        DiscRecPtr  LR,R6
        LDRB    R0,[LR,#Priority]
        TEQS    R0,#0
        BEQ     %FT95

        MOV     R5,#0           ; error accumulator

        BL      CloseAllByDisc  ;(R1->R0,V)
        MOVVS   R5,R0

 [ Module_Version >= 205
  [ DebugL
        DREG    R6, "Dismounting disc "
  ]
        ; Test for defect list presence properly
        DiscRecPtr  LR, R6
        LDRB    R7, [LR, #DiscsDrv]
  [ DebugL
        DREG    R7, "  = drive "
  ]
        ; If not attached to a drive skip drive specific sequence
        TEQ     R7, #8
        BEQ     %FT50

        DrvRecPtr  R2, R7

        ; Clear the LastDiscOpWasFormat flag
        LDRB    LR, [R2, #DrvFlags]
        BIC     LR, LR, #LastDiscOpWasFormat
        STRB    LR, [R2, #DrvFlags]
 [ DebugL
        DLINE   "LastDiscOpWasFormat clear (D)"
 ]

        ; Park disc if has defect list
        TST     LR, #HasDefectList
        MOVNE   R1, #SeekOp :OR: NoEscape;if winnie seek to park address given
        LDRNE   R2, DefectSpace         ;in defect Map
        ADDNE   R2, SB, R2
        ASSERT  SzDefectList = (1 :SHL: 9)
        ADDNE   R2, R2, R7, LSL #9
        LDRNE   R2, [R2,#ParkDiscAdd]

 [ BigDisc
	BEQ	%FT04                   ; no parking needed
	DiscRecPtr LR,R6                ; get disc record ptr
	LDR	R0, [LR, #DiscSize2]    ; get discsize2
	MOVS	R0, R0                  ; is it big?
	LDREQ	R0, [LR, #DiscSize]
        TSTEQS  R0, #DiscBits           ; if so then dismount
	LDREQB	LR, [LR,#SectorSize]
	MOVEQ	R2, R2, LSR LR
        ORR     R2, R2, R6, LSL #(32-3)
  [ DebugL
        BEQ     %FT01
        DREG    R2, "Parking at address "
01
  ]
        BL      DoDiscOp                ;(R1-R4->R0-R4)
04
 |
        ORRNE   R2, R2, R6, LSL #(32-3)
  [ DebugL
        BEQ     %FT01
        DREG    R2, "Parking at address "
01
  ]
        BLNE    DoDiscOp                ;(R1-R4->R0-R4)
 ]

 |
        LDRB    LR, Winnies
        CMPS    R1, LR           ;also V=0

        MOVCC   R1, #SeekOp :OR: NoEscape;if winnie seek to park address given
        LDRCC   R2, DefectSpace         ;in defect Map
        ADDCC   R2, SB, R2
        ASSERT  SzDefectList=&200
        ADDCC   R2, R2, R6,LSL #9
        LDRCC   R2, [R2,#ParkDiscAdd]
        ORRCC   R2, R2, R6,LSL #(32-3)
        BLCC    DoDiscOp                ;(R1-R4->R0-R4)
 ]
        MOVVS   R5, R0

50
        MOV     R0, R6
        BL      FreeDiscRec     ;(R0)

        MOV     R0, R5
95
        BL      SetVOnR0
        STRVS   R0, [SP]
 [ Module_Version >= 205
        Pull    "R0-R7,PC"
 |
        Pull    "R0-R6,PC"
 ]


; >>>>>>>
; DoDrive
; >>>>>>>

DoDrive ROUT
        Entry   Flag,Dormant    ;leaves SB,LR stacked
        MOV     R1, R0          ;string ptr
        BL      ParseAnyDrive   ;(R1->R0,Z,C,V)
        STRVCB  R0, Drive
        BLVS    FindErrBlock    ;(R0->R0,V)
        BL      FileCoreExit
        Pull    "SB,PC"


; =======
; Confirm
; =======

; exit V=1 <=> error
; Z=1 <=> confirmed

TerseConfirm ROUT       ;entry V=0
        Push    "R0,LR"
        B       %FT10

ConfirmText Text "AreYouSure"

Confirm                 ;entry V don't care
        Push    "R0,LR"
        ADR     r0, ConfirmText
        BL      message_gswrite0
10
 [ MOS_Version > 120
        MOVVC   r0, #15
        MOVVC   r1, #1
        SWIVC   XOS_Byte
        SWIVC   XOS_Confirm
        BLVC    ConvertEscapeToError
 |
        BLVC    FlushAndReadChar
 ]

        MOV     r1, pc
        SWIVC   XOS_WriteC
        SWIVC   XOS_NewLine

        ORRVS   r1, r1, #V_bit
        BICVS   r1, r1, #Z_bit  ; NE on error
        TEQP    pc, r1
        STRVS   R0, [SP]
        Pull    "R0,PC"


; ================
; FlushAndReadChar
; ================

;In:
;Out: r0 = char read or VS and r0=error (includes escapes)
FlushAndReadChar ROUT
        Push    "R1,R2,LR"
        MOV     R0, #15
        MOV     R1, #1
        BL      OnlyXOS_Byte
        BLVC    DoXOS_ReadC
        BLVC    ConvertEscapeToError
        Pull    "R1,R2,PC"

; ====================
; ConvertEscapeToError
; ====================

; In: VC and C=escape was pressed
; Out: r0=escape error is CS in

ConvertEscapeToError ROUT
        MOVCC   pc, lr
        Push    "r1,r2,lr"

        ; Acknowledge the escape
        MOV     r0, #OsbyteAckEscape
        BL      OnlyXOS_Byte

        ; Convert to error
        MOVVC   r0, #ExtEscapeErr
        SETV

        Pull    "r1,r2,pc"


; >>>>>>
; DoFree
; >>>>>>

FC0     DCB     "FC0",0
FC1     DCB     "FC1",0
FCK0    DCB     "FCK0",0
FCK1    DCB     "FCK1",0
        ALIGN

DoFree ROUT
        Entry   Flag, Dormant    ;leaves SB,LR stacked

        MOV     r5, sp

        MOV     r1, r0
        BL      strlen
        MOV     r2, r3
        LDR     r1, FS_Title
        BL      strlen
        ADD     r3, r3, r2
        ADD     r3, r3, #2 + 1 + 3      ; 2 for ::, one for terminator, 3 for round-up
        BIC     r3, r3, #3

        SUB     sp, sp, r3
        MOV     r2, r1                  ; FS_Title
        MOV     r1, sp
        BL      strcpy
        BL      strlen
        ADD     r1, r1, r3
        MOV     lr, #":"
        STRB    lr, [r1], #1            ; :

        LDRB    lr, [r0]                ; 2nd : if disc specifier present
        CMP     lr, #' '
        MOVHI   lr, #':'
        STRHIB  lr, [r1], #1

        MOV     r2, r0
        LDRB    lr, [r2]                ; disc specifier (excluding : prefix)
        TEQ     lr, #":"
        ADDEQ   r2, r2, #1
        BL      strcpy

        MOV     r1, sp

 [ BigDisc
        MOV     r6, r0                  ; keep copy of command tail ptr
        MOV     r0, #FSControl_ReadFreeSpace64  ; get the full free space info
  [ DebugQ
        DSTRING r1, "ReadFreeSpace on "
  ]
        BL      DoXOS_FSControl
        BVC     %FT01   ; if no error then do not try the other FSControl

; here, we have a FS which doesn't support FSControl_ReadFreeSpace64 - try
; FSControl_ReadFreeSpace

        MOV     r0, #FSControl_ReadFreeSpace
        MOV     r1, sp                  ; restore FS name
        MOV     r2, r6                  ; restore command tail
        BL      DoXOS_FSControl

; now munge results
        MOV	r4, #0			; high 32 0
	MOV	r3, r2			; low 32
	MOV	r2, r1			; max object size
	MOV	r1, #0			; high 32 0

01
  [ DebugQ
        DREG    r0, "FreeSpace is (",cc
        DREG    r1, "",cc
        DREG    r2, ",",cc
        DREG    r3, ",",cc
        DREG    r4, "",cc
        DLINE   ")"
  ]

 |
        MOV     r0, #FSControl_ReadFreeSpace
  [ DebugQ
        DSTRING r1, "ReadFreeSpace on "
  ]
        BL      DoXOS_FSControl
  [ DebugQ
        DREG    r0, "FreeSpace is (",cc
        DREG    R1, ",",cc
        DREG    R2, ",",cc
        DLINE   ")"
  ]

 ]

        MOV     sp, r5

        BVS     %FT80

 [ BigDisc
; first, determine whether big or not.  By big here we mean >4G
        CMPS    r4, #0
        MOV     r7, r4
        BEQ     %FT50

; big disc
        SUBS    r2, r3, r0
        SBC     r3, r4, r1
; now r0,r1=free space and r2,r3=used space
        baddr   r5, FCK0
        BL	%FT90
	MOVVC	r0, r2
	MOVVC	r1, r3
	baddr	r5, FCK1, VC
	BLVC	%FT90
        B       %FT80
50
; small disc
        SUB     r3, r3, r0
        baddr   r5, FC0
        BL      %FT90
        MOVVC   r0, r3
        MOVVC   r1, #0
        baddr   r5, FC1, VC
        BLVC    %FT90
 |
        SUB     r3, r2, r0
        baddr   r5, FC0
        BL      %FT90
        MOVVC   r0, r3
        baddr   r5, FC1, VC
        BLVC    %FT90
 ]

80
        BLVS    FindErrBlock            ;(R0->R0,V)
        BL      FileCoreExit
        Pull    "SB,PC"

 [ BigDisc
; entry r0,r1=number to subst Hex16 into %0 and right justified formatted 4byte cardinal into %1 (Kbytes)
;      r7!=0 implies big disc
;        ==0 implies small disc
;       r5 = tag
; exit  r1,r4-r6 trashed
 |
; entry r0=number to subst Hex8 into %0 and right justified formatted 4byte cardinal into %1
;       r5 = tag
; exit  r1-r2,r4-r6 trashed
 ]
90
 [ BigDisc
        Push    "r0,r2,lr"
        SUB     sp, sp, #52                             ; Make a frame to do the conversions into
 |
        Push    "r0,lr"
        SUB     sp, sp, #28                             ; Make a frame to do the conversions into
 ]

        ; Convert into Hex and Decimal
        MOV     r4, r0
 [ BigDisc
; do hex number of bytes; do M.S. word first then tack on L.S. word
        MOV     r6, r1
        MOVS    r7, r7
        BEQ     %FT10
        MOV     r0, r1
        ADD     r1, sp, #16
        MOV     r2, #12
        SWI     XOS_ConvertHex8
        BVS     %FT99
        MOV     r0, r4
        ADD     r1, sp, #24
        MOV     r2, #12
        SWI     XOS_ConvertHex8
        B       %FT20
10
        MOV     r0, r4
        ADD     r1, sp, #16
        MOV     r2, #12
        SWI     XOS_ConvertHex8

20
 |
        ADD     r1, sp, #16
        MOV     r2, #12
        SWI     XOS_ConvertHex8
 ]

 [ BigDisc
        ; first generate number of Kbytes in r0
        BVS     %FT99           ; skip code that may corrupt VS state if already VS
        MOVS    r7, r7          ; check for big/small
        MOVEQ   r0, r4          ; if small then L.S only
        MOVNE   r0, r4, LSR #10 ; else shift right by 10 and combine
        ORRNE   r0, r0, r6, LSL #22 ; with L.S. word shifted
; now have either number of bytes or number of Kbytes as appropriate in r0

        MOV     r1, sp
        MOV     r2, #16
        BL      ConvertFormattedCardinal4
        BVS     %FT99
 |
        MOVVC   r0, r4
        MOVVC   r1, sp
        MOVVC   r2, #16
        BLVC    ConvertFormattedCardinal4
        BVS     %FT99
 ]

 [ DebugQ
        DLINE   "Conversions performed successfully"
 ]

        ; Copy decimal to end of buffer
92
        LDRB    lr, [r1], #-1
        STRB    lr, [r1, r2]
        CMP     r1, r0
        BHS     %BT92

 [ DebugQ
        DLINE   "Copied to end of buffer"
 ]

        ; Pad before with spaces
        MOV     lr, #" "
95
        SUBS    r2, r2, #1
        STRHIB  lr, [r1, r2]
        BHI     %BT95

 [ DebugQ
        DLINE   "Padded"
 ]

        MOV     r0, r5
        ADD     r4, sp, #16
        ADD     r5, sp, #2      ; Right justify into a 11-2=9 width field (11 = 12-1 for the terminator)
        BL      message_gswrite02

99
 [ BigDisc
        ADD     sp, sp, #52
        STRVS   r0, [sp]
        Pull    "r0,r2,pc"
 |
        ADD     sp, sp, #28
        STRVS   r0, [sp]
        Pull    "r0,pc"
 ]

ConvertFormattedCardinal4 ROUT
        ;       R0 is the value to convert
        ;       R1 is the buffer to convert into
        ;       R2 is the buffer size
        ;       Returns
        ;       R0 entry value of R1
        ;       R1 pointer to terminating zero
        ;       R2 size remaining in buffer, R2'=R2-(R1'-R0')

FormatFrameSize * 16

        Push    "r1, r2, r3, r4-r9, lr"                 ; R3 only there to make frame right
        DEC     sp, FormatFrameSize                     ; Frame for doing the conversion into
        MOV     r2, #FormatFrameSize - 1
FakeErrorCDATBufferOverflow
        MOV     r1, sp
        SWI     XOS_ConvertCardinal4
        SUBVC   r4, r1, r0                              ; Calculate the number of digits returned
        MOVVC   r0, #-1                                 ; Current territory
        MOVVC   r1, #1                                  ; Thousands separator
        SWIVC   XTerritory_ReadSymbols
        MOVVC   r5, r0                                  ; Save pointer
        MOVVC   r0, #-1                                 ; Current territory
        MOVVC   r1, #2                                  ; Character grouping
        SWIVC   XTerritory_ReadSymbols
        BVS     ExitConvertFormatted
        MOV     r6, r0                                  ; Save pointer
        SUB     r7, r5, #1                              ; Measure the separator string
SeparatorCountLoop
        LDRB    r0, [ r7, #1 ]!
        TEQ     r0, #0
        BNE     SeparatorCountLoop
        SUB     r7, r7, r5                              ; Compute the length
        ; Work out how long the result will be
        MOV     r8, r4                                  ; Length of result
        MOV     r9, r6                                  ; Grouping format pointer
        MOV     r2, #0                                  ; Current group size
        MOV     r1, #0                                  ; Distance along the source
FormatCountLoop
        LDRB    r14, [ r9 ]
        TEQ     r14, #0
        MOVNE   r2, r14                                 ; Use this grouping
        ADDNE   r9, r9, #1                              ; Ready for the next grouping
        TEQ     r2, #0                                  ; Don't do anything if format defective
        BEQ     FormatCountDone
        ADD     r1, r1, r2
        CMP     r1, r4                                  ; Would this group put us beyond the string?
        ADDLT   r8, r8, r7                              ; Add the separator length to the string
        BLT     FormatCountLoop
FormatCountDone
        ADD     r14, sp, #FormatFrameSize               ; Entry R1
        LDMIA   r14, { r1, r2 }
        SUB     r2, r2, r8
        CMP     r2, #1                                  ; Allow for the terminating zero
        MOVMI   r2, #1                                  ; Make a buffer that is too small
        MOVMI   r0, #100                                ; For this result
        BMI     FakeErrorCDATBufferOverflow
        ADD     r1, r1, r8
        ADD     r14, sp, #FormatFrameSize + 4           ; Exit R1
        STMIA   r14, { r1, r2 }
        ADD     r4, sp, r4                              ; Trailing zero of converted source string
        MOV     r2, #0                                  ; Current group size
        STRB    r0, [ r1 ], #-1                         ; Put the terminator on the destination
FormatCopyLoop
        LDRB    r14, [ r6 ]
        TEQ     r14, #0
        MOVNE   r2, r14                                 ; Use this grouping
        ADDNE   r6, r6, #1                              ; Ready for the next grouping
        TEQ     r2, #0                                  ; Don't do anything if format defective
        MOVEQ   r2, #-1
        MOV     r9, r2                                  ; R2 is the number of chars to copy across
CharacterCopyLoop
        LDRB    r14, [ r4, #-1 ]!
        STRB    r14, [ r1 ], #-1
        TEQ     r4, sp                                  ; Have we reached the last character?
        BEQ     FinishConvertFormatted
        SUBS    r9, r9, #1
        BNE     CharacterCopyLoop
        MOVS    r0, r7                                  ; Length of the separator
        BEQ     CharacterCopyLoop                       ; No separator to copy
SeparatorCopyLoop
        SUBS    r0, r0, #1
        LDRB    r14, [ r5, r0 ]
        STRB    r14, [ r1 ], #-1
        BNE     SeparatorCopyLoop
        B       FormatCopyLoop                          ; Start back again

FinishConvertFormatted
        CLRV
ExitConvertFormatted
        INC     sp, FormatFrameSize
        STRVS   r0, [ sp, #0 ]
        Pull    "r0, r1, r2, r4-r9, pc"


; >>>>>
; DoMap
; >>>>>

MC0     DCB     "MC0",0
MC1     DCB     "MC1",0
MC2     DCB     "MC2",0
MC3     DCB     "MC3",0
        ALIGN

DoMap ROUT
        Entry   Flag,Dormant     ;leaves SB,LR stacked
        Push    "R7-R11"
 [ BigDisc
        SUB     SP, SP, #40     ;string buffer
 |
        SUB     SP, SP, #20     ;string buffer
 ]
        CMPS    R1, #0          ;V=0
        BLEQ    IdentifyCurrentDisc     ;(->R0,R3,V)
        BVS     %FT95
        BEQ     %FT05
        MOV     R1, R0
        MOV     R2, #MustBeDisc
        BL      FullLookUp              ;(R1,R2->R0-R6,C,V)
        BVS     %FT95
05
 [ Module_Version >= 205
        BL      DiscMustBeFileCore      ;(R3->V,R0)
        BVS     %FT95
 ]
        BL      DiscAddToRec            ;(R3->LR)
        LDRB    r2, [LR, #DiscFlags]
        TSTS    r2, #OldMapFlag
        BNE     %FT06
        TST     r2, #OldDirFlag
        baddr   r0, MC3, EQ     ;(   start,  length) new map, new directories
        baddr   r0, MC2, NE     ;(   start,  length) new map, old directories
        B       %FT07
06
        TST     r2, #OldDirFlag
        baddr   r0, MC1, EQ     ;(   start,  length) old map, new directories
        baddr   r0, MC0, NE     ;(   start,  length) old map, old directories
07
        BL      message_gswrite0

 [ BigDisc
; find the disc record
        BL      DiscAddToRec            ; get the disc record
        LDR     R2, [LR, #DiscSize2]    ;
        MOVS    R2, R2
        MOVNE   R0, #28                 ;field width (Big Disc)
        MOVEQ   R0, #20                 ;field width (Small Disc)
        MOV     R2, #0
 |
        MOV     R2, #0
        MOV     R0, #20                 ;field width
 ]
        BL      ScreenFormat            ;(R0->R9-R11)
        ADD     R10,R10,#1              ;separating space
        BL      %FT99
        MOV     LR, #1
        STRB    LR, LastReEnter
10
        BL      BeforeReadFsMap         ;(R3->R0,V)
        BVS     %FT95
        LDRB    LR, LastReEnter
        TEQS    LR, #0
        MOVNE   LR, #0
        STRNEB  LR, LastReEnter
 [ NewFs
        BLNE    InitReadFs              ;(R3->R9-R11)
 |
        BLNE    InitReadOldFs           ;(R3->R9-R11)
 ]
15
 [ NewFs
        BL      NextFs                  ;(R3,R9-R11->R7-R11,Z)
 |
        BL      NextOldFs               ;(R3,R10,R11->R7,R8,R11,Z)
 ]
        BIC     R8, R8, #DiscBits
        BLEQ    UnlockMap
        BEQ     %FT20
        CMPS    R8, R2
        BLS     %BT15
        BL      UnlockMap
        MOV     R2, R8
        MOV     R1, R7
        MOV     R7, SP
        MOV     LR, #"("
        STRB    LR, [R7],#1
	MOV	R0, R8

 [ BigDisc ; SBP: Thu 15th December 1994 - walked thru, doesn't seem
; to support >4G discs.  Changed to support them.
	Push	"R1,R2"
        LDR     R1, [R10, #ZoneHead+DiscSize2]    ; discsize2 field
        MOVS    R1, R1
        BEQ     %FT18                   ; small disc
	LDRB	LR,[R10,#ZoneHead+SectorSize]	; sector size
	MOV	R1, R0,LSL LR
        RSB     LR, LR, #32
        MOVS    R0, R0, LSR LR
        BEQ     %FT16                   ; don't print number - pad spaces
	BL	PutHex2
        MOV     R0, R1
        BL      PutHexWord
        B       %FT19

; here when low address on big disc - pad with 8 spaces
16
        MOV     R0, #8
        MOV     LR, #' '
17
        STRB    LR, [R7],#1
        SUBS    R0, R0, #1
        BNE     %BT17
        MOV     R0, R1
        BL      PutHex2
        B       %FT19

; here when small disc
18
	LDRB	LR,[R10,#ZoneHead+SectorSize]	; sector size
        MOV     R0, R0, LSL LR
        BL      PutHex2
; here when finished address and want to do length
19
	Pull	"R1,R2"
 |
        BL      PutHex2         ;(R0,R7->R7)
 ]
        MOV     R0, #","
        STRB    R0, [R7],#1
        MOV     R0, R1
        BL      PutHex2         ;(R0,R7->R7)
        MOV     LR, #")"
        STRB    LR, [R7],#1
        MOV     LR, #0
        STRB    LR, [R7],#1
        MOV     R7 ,SP
        BL      WriteString     ;(R7->R0,V)
        BL      %FT99
        BLVC    NextField       ;(R9-R11->R0,R11,V)
        BL      %FT99
        BVS     %FT95
        B       %BT10

20
        CMPS    R4, R6          ;V=0
        BLNE    DoXOS_NewLine   ;(->R0,V)
95
        BLVS    FindErrBlock    ;(R0->R0,V)
 [ BigDisc
        ADD     SP, SP, #40
 |
        ADD     SP, SP, #20
 ]
        BL      FileCoreExit
        Pull    "R7-R11,SB,PC"

99                      ;swap R4-R6 with R9-R11
        Push    "R4-R6,R9-R11,LR"
        Pull    "R9-R11"
        Pull    "R4-R6,PC"


RootText
 =       RootChar,0
        ALIGN

; >>>>>>>
; DoMount
; >>>>>>>

DoMount ROUT
        Push    "lr"
        MOV     r6, sp          ; Initial SP
 [ DebugQ
        DREG    r6, "r6 start "
 ]

        ; Convert no parameter to *mount <drive>
        TEQ     r1, #0
        LDREQ   r12, [r12]
        LDREQB  lr, Drive
        ASSERT  ("0" :AND: 7)=0
        EOREQ   lr, lr, #"0" :EOR: 4
        Push    "lr", EQ
        MOVEQ   r0, sp

        MOV     r1, r0

        ; Calculate the length required
        MOV     r2, #?RootLibText + 1 + 3   ; includes 0 terminator, 1 for . and 3 for rounding up
        MOV     r0, r1
10
        LDRB    lr, [r0], #1
        CMP     lr, #" "
        TEQHI   lr, #DeleteChar
        ADDHI   r2, r2, #1
        BHI     %BT10

        ; Ensure enough space for the : prefix
        LDRB    lr, [r1]
        TEQ     lr, #":"
        ADDNE   r2, r2, #1

        BIC     r2, r2, #3
        SUB     sp, sp, r2

        MOV     r2, sp


        ; :<disc>

        MOVNE   lr, #":"
        STRNEB  lr, [r2], #1

        MOV     r0, r1
20
        LDRB    lr, [r0], #1
        CMP     lr, #" "
        TEQHI   lr, #DeleteChar
        STRHIB  lr, [r2], #1
        BHI     %BT20

        ; .
        MOV     lr, #"."
        STRB    lr, [r2], #1

        ; Save position for later
        MOV     r3, r2

        ; $\0
        MOV     lr, #"$"
        STRB    lr, [r2], #1
        MOV     lr, #0
        STRB    lr, [r2], #1

        ; *Dir :<disc>.$
        MOV     r0, #FSControl_Dir
        MOV     r1, sp
 [ DebugQ
        DSTRING r1, "*Dir "
 ]
        SWI     XOS_FSControl
        BVS     %FT90

        baddr   r0, RootLibText
        MOV     r2, r3
30
        LDRB    lr, [r0], #1
        STRB    lr, [r2], #1
        TEQ     lr, #0
        BNE     %BT30

        ; Junk errors returned from these calls...

        ; *Lib :<disc>.$
        MOV     r0, #FSControl_Lib
        MOV     r1, sp
 [ DebugQ
        DSTRING r1, "*Lib "
 ]
        SWI     XOS_FSControl

        ; *NoURD
        MOV     r0, #FSControl_NoURD
 [ DebugQ
        DLINE   "*NoURD"
 ]
        SWI     XOS_FSControl

        CLRV

90
 [ DebugQ
        DREG    r6, "r6 end "
 ]
        MOV     sp, r6
        Pull    "pc"


; >>>>>>>>>>
; DoNameDisc
; >>>>>>>>>>

DoNameDisc ROUT
DoNameDisk
        Push    "r0-r4,lr"

        MOV     r4, sp

        ; Find length of 1st string
        MOV     r3, #0
        MOV     r1, r0
10
        LDRB    lr, [r1], #1
        CMP     lr, #" "
        ADDHS   r3, r3, #1
        BHS     %BT10

        ; Skip to 1st non-space
20
        LDRB    lr, [r1], #1
        TEQ     lr, #" "
        BEQ     %BT20

        SUB     r1, r1, #1

        ; Add length of 2nd string
30
        LDRB    lr, [r1], #1
        CMP     lr, #" "
        ADDHI   r3, r3, #1
        BHI     %BT30

        ; Add enough for an extra :, \0 terminators and 3 for the round-up
        ADD     r3, r3, #1+1+1+3
        BIC     r3, r3, #3
        SUB     sp, sp, r3

        ; Copy the 1st string, adding a : if there isn't one already
        MOV     r2, sp
        LDRB    lr, [r0]
        TEQ     lr, #":"
        MOVNE   lr, #":"
        STRNEB  lr, [r2], #1

40
        LDRB    lr, [r0], #1
        CMP     lr, #" "
        STRHIB  lr, [r2], #1
        BHI     %BT40
        MOV     lr, #0
        STRB    lr, [r2], #1

        MOV     r1, r2

        ; Copy the 2nd string

        ; Skip to 1st non-space
60
        LDRB    lr, [r0], #1
        TEQ     lr, #" "
        BEQ     %BT60

        SUB     r0, r0, #1

70
        LDRB    lr, [r0], #1
        CMP     lr, #" "
        STRHIB  lr, [r1], #1
        BHI     %BT70
        MOV     lr, #0
        STRB    lr, [r1], #1


        ; Do the FSControl

        MOV     r0, #FSControl_NameDisc
        MOV     r1, sp

 [ DebugQ
        DREG    r0, "OS_FSControl(",cc
        DSTRING r1, ",",cc
        DSTRING r2, ",",cc
        DLINE   ")"
 ]
        SWI     XOS_FSControl

        MOV     sp, r4
        STRVS   r0, [sp]
        Pull    "r0-r4,pc"

VerifyStr
 = "VC0",0      ;Verifying ...
VerOk
 = "VC1",0      ;Verified OK
VerRetries
 = "VC2",0      ;Verified with retries
VerBad
 = "VC3",0      ;Verify failed
        ALIGN

; >>>>>>>>
; DoVerify
; >>>>>>>>

DoVerify ROUT
        Entry  Flag,Dormant     ;leaves SB,LR stacked
        Push    "R7-R11"
        TEQS    R1, #0
        BLEQ    IdentifyCurrentDisc     ;(->R0,R3,V)
        MOVNE   R2, #MustBeDisc
        MOVNE   R1, R0
        BLNE    FullLookUp      ;(R1,R2->R0-R6,V)
        baddr   R0, VerifyStr,VC
        BLVC    message_gswrite0
        MOVVC   R1, #RestoreOp
        AND     R2, R3, #DiscBits
        BLVC    DoDiscOp        ;(R1-R4->R0,R2-R4,V)
        BVS     %FT85

        MOV     R1, #VerifyOp
        MOV     R6, #0          ;clear error flag

;        BL      DiscMustBeFileCore      ; check if not filecore disc.

;        BVS     %FT70
 [ NewFs
        BL      TestMap         ;(R3->Z)
        BNE     %FT50

        ; Verify new map
        BL      BeforeReadFsMap ;(R3->R0,V)
        BVS     %FT85
        BL      CritInitReadNewFs       ;(->R10,R11)

        SUBS    R0, R0, R0      ;init zone = 0, Z=0, C=1, HS
        B       %FT30

10
        ADD     R11,R11,R7
20
        CMPS    R11,R5
        ADDHS   R0, R0, #1
30
 [ DebugQ
        DREG    R0, "Verify zone "
 ]
        BLHS    InitZoneObj     ;(R0,R10->R8,R9,R11,LR)
        MOVHS   R5, LR
        LDRHSB  LR, [R10,#ZoneHead+Zones]
        CMPHSS  R0, LR
        MOVHS   R7, #0
        BHS     %FT40

        BL      RdLenLinkBits   ;(R10,R11->R7,R8)
        TEQS    R8, #1
        BNE     %BT10           ; Not a bad block

40
        ; Verify to 'here'
        MOV     R9, R0
        BL      MapPtrToDiscAdd ;(R3,R10,R11->R0)
        ADD     R11,R11,R7

 [ BigDisc ;SBP: Thu 15th December 1994 - walked thru, looks OK
        SUBS    R4, R0, R2      ;length to verify
	LDRB	LR, [R10, #ZoneHead+SectorSize]
	MOV	R4, R4, LSL LR	;get transfer length in bytes
        BLHI    %FT90           ;verify this chunk
 |
        SUBS    R4, R0, R2      ;length to verify
        BLHI    %FT90           ;verify this chunk
 ]

        ; If bad block is last in zone skip ZoneSpare into next zone
        CMP     R11, R5
        ASSERT  ZoneSpare :MOD: 4 = 2
        LDRHS   LR, [R10, #ZoneHead + ZoneSpare]
        ADDHS   R11, R5, LR, LSR #16            ; Offset from R5 just in case R11 overhangs into the ZoneSpare

        BL      MapPtrToDiscAdd ;(R3,R10,R11->R0) disc add after defect
        MOV     R2, R0
        MOV     R0, R9
        TEQS    R8, #1
        BEQ     %BT20

        CMPS    R6, #1
        baddr   R0, VerOk, LO
        baddr   R0, VerRetries, EQ
        baddr   R0, VerBad, HI
        BL      message_gswrite0
        ALIGN

        B       %FT80

50
 ]
        BL      SizeLessDefects         ;(R3->LR)
        MOV     R4, LR
        BL      %FT90
60
        CMPS    R6, #1
        baddr   R0, VerOk, LO
        baddr   R0, VerRetries, EQ
        baddr   R0, VerBad, HI
        BL      message_gswrite0
        ALIGN

        B       %FT85

80
;        DLINE   "DoVerify: Calling UnlockMap"
        BL      UnlockMap
;        DLINE   "DoVerify: Done UnlockMap"
85
        BLVS    FindErrBlock            ;(R0->R0,V)
        BL      FileCoreExit
        Pull    "R7-R11,SB,PC"

90
        Push    "R0,R3,R5,R7-R9,LR"
 [ DebugQ
        DREG    R1, "Verify chunk:",cc
        DREG    R2, ",",cc
        DREG    R4, ","
 ]
        BL      DiscAddToRec    ;(R3->LR)
        MOV     R5, LR
        MOV     R9, #-1
92
        MOV     R3, #0
        BL      DoDiscOp        ;(R1-R4->R0-R4,V)
        BVC     %FT99
        TSTS    R0, #DiscErrorBit
        BEQ     %FT99
        Push    "R1,R2"
        MOV     R1, #RestoreOp
        BL      DoDiscOp        ;(R1-R4->R0-R4,V)
        Pull    "R1,R2"
        BVS     %FT99
        TEQS    R2, R9
        BEQ     %FT96

        ORR     R6, R6, #1
        MOV     R8, #VerifyRetries
        MOV     R9, R2
        BL      DoXOS_NewLine   ;(->R0,V)
 [ BigDisc ;SBP: Thu 15th December 1994 Walked thru, push/pull of R1 not
; needed - use R3 instead
	BVS	%FT95
        BIC     R0, R2, #DiscBits
	LDRB	LR, [R5,#SectorSize]
	MOV	R3, R0, LSL LR	;bottom 32 bits of addr
	RSB	LR, LR, #32	;shift to get top 32 bits of addr
	MOV	R0, R0, LSR LR	;top 32 bits
        BL      WrHex           ;(R0->R0,V) - do top 32 bits of number
	MOVVC	R0,R3		; - do bottom 32 bits
	BLVC	WrHex		;
        BLVC    DoSpace         ;(->R0,V)
 |
        BICVC   R0, R2, #DiscBits
        BLVC    WrHex           ;(R0->R0,V)
        BLVC    DoSpace         ;(->R0,V)
 ]
94
        MOVVC   R0, #"?"
        BLVC    DoXOS_WriteC    ;(R0->R0,V)
 [ BigDisc
95
 ]
        BVS     %FT99
        B       %BT92

96
        SUBS    R8, R8, #1
        BNE     %BT94           ;V=0

        ORR     R6, R6, #2
        MOV     R8, #VerifyRetries
        BL      FindErrBlock    ;(R0->R0,V)
        ADD     R7, R0, #4      ;also set error flag
        MOV     R0, #CR
        BL      DoXOS_WriteC    ;(R0->R0,V)
        BLVC    WriteString     ;(R7->R0,V)
        BVS     %FT99

        LDRB    LR, [R5,#SectorSize]
        MOV     R0, #1
 [ BigDisc ; SBP: Thu 15th December 1994 - walked thru, looks OK
        ADD     R2, R2, R0
        SUBS    R4, R4, R0, LSL LR      ;also V=0
 |
        ADD     R2, R2, R0, LSL LR
        SUBS    R4, R4, R0, LSL LR      ;also V=0
 ]
        BGT     %BT92
99
        Pull    "R0,R3,R5,R7-R9,PC",VC
        ADD     SP, SP, #7*4
        B       %BT80

        LTORG
        END
