10 REM > IDE/s
   20 REM IDE interface at &FC40-4F
   30 :
   40 REM 01-May-2004 v0.10 JGH: Initial version based on RAMCard
   50 REM 24-May-2004 v0.11 JGH: Reading works
   60 REM 20-Dec-2004 v0.12 JGH: Geometry 64*4*cylinder
   70 :
   80 ver$="0.12"
   90 ON ERROR REPORT:PRINT ERL:END
  100 :
  110 REM Workspace contents:
  120 REM ws+&000 - RAMCard b0-b7
  130 REM ws+&001 - RAMCard b0-b7
  140 REM ws+&002 - RAMCard b0-b7
  150 REM ws+&003 -> intercepted
  160 REM ws+&004 - RAMCard size
  170 REM ws+&008 - RAMCard memory address/file buffer
  180 REM ws+&00C - RAMCard pathname
  190 REM ws+&010 - File PTR, byte 0 holds flags:
  200 REM           b0=buffer read, b1=buffer needs writing
  210 REM
  220 REM ws+&020 - IDE device 0 size
  230 REM ws+&024 - IDE device 0 memory address/file buffer
  240 REM ws+&028 - IDE device 0 pathname
  250 REM ws+&02C - IDE device 0 PTR
  260 REM
  270 REM ws+&030 - IDE device 1 size
  280 REM ws+&034 - IDE device 1 memory address/file buffer
  290 REM ws+&038 - IDE device 1 pathname
  300 REM ws+&03C - IDE device 1 PTR
  310 REM
  320 REM ws+&040 -> intercepted -> IDE data even bytes (holds current command)
  330 REM ws+&041 - IDE Error
  340 REM ws+&042 - IDE Count
  350 REM ws+&043 - IDE Sector         LBA b0-b7
  360 REM ws+&044 - IDE Cylinder Low   LBA b8-b15
  370 REM ws+&045 - IDE Cylinder High  LBA b16-b23
  380 REM ws+&046 - IDE Head+Drive     LBA b24-b27
  390 REM ws+&047 - IDE Status
  400 REM ws+&048 -> intecepted -> IDE data odd bytes
  410 REM ws+&049 -
  420 REM ws+&04A -
  430 REM ws+&04B -
  440 REM ws+&04C -
  450 REM ws+&04D -
  460 REM ws+&04E - [Alternative Status]
  470 REM ws+&04F - [Drive Data]
  480 :
  490 Service_6502Base=&80AD0
  500 DIM mcode% &8000
  510 sp=13:link=14:pc=15
  520 FOR p=0 TO 1
  530   P%=0:O%=mcode%
  540   [OPT p*3+4
  550   EQUD 0:\start
  560   EQUD Initialise
  570   EQUD Finalise
  580   EQUD Service
  590   EQUD TitleStr
  600   EQUD HelpStr
  610   EQUD CommandTable
  620   EQUD 0:\ SWI chunk number
  630   EQUD 0:\ SWI chunk handler
  640   EQUD 0:\ SWI decoding table
  650   EQUD 0:\ SWI decoding code
  660   :
  670   .TitleStr
  680   EQUS "BBCIDECard"
  690   EQUB 0
  700   ALIGN
  710   .HelpStr
  720   EQUS "BBCIDECard"+CHR$9+ver$+" ("+MID$(TIME$,5,11)+")"
  730   EQUB 0
  740   ALIGN
  750   :
  760   .CommandTable
  770   EQUS "BBCIDE":EQUB 0:ALIGN:EQUD BBCIDE
  780   EQUD &00010001:EQUD BBCIDE_Syntax:EQUD BBCIDE_Help
  790   :
  800   EQUS "BBCIDELoad":EQUB 0:ALIGN:EQUD BBCIDELoad
  810   EQUD &00010001:EQUD BBCIDELoad_Syntax:EQUD BBCIDELoad_Help
  820   :
  830   EQUS "BBCIDESave":EQUB 0:ALIGN:EQUD BBCIDESave
  840   EQUD &00010001:EQUD BBCIDESave_Syntax:EQUD BBCIDESave_Help
  850   EQUB 0:ALIGN
  860   :
  870   .BBCIDE_Help
  880   EQUS "Specifies a BBCIDE image to access":EQUB 13
  890   .BBCIDE_Syntax
  900   EQUS "Syntax: BBCIDE <afsp>":EQUB 13
  910   EQUB 0:ALIGN
  920   :
  930   .BBCIDELoad_Help
  940   EQUS "Loads data into a BBCIDE":EQUB 13
  950   .BBCIDELoad_Syntax
  960   EQUS "Syntax: BBCIDELoad <afsp>":EQUB 13
  970   EQUB 0:ALIGN
  980   :
  990   .BBCIDESave_Help
 1000   EQUS "Saves data from a BBCIDE":EQUB 13
 1010   .BBCIDESave_Syntax
 1020   EQUS "Syntax: BBCIDESave <afsp>":EQUB 13
 1030   EQUB 0:ALIGN
 1040   :
 1050   :
 1060   .Initialise
 1070   stmfd  (sp)!,{link}
 1080   ldr    r0,[r12]
 1090   orrs   r0,r0,#0
 1100   bne    Reinitialise  ; We already have workspace
 1110   mov    r3,#256       ; We want 256 bytes
 1120   mov    r0,#6
 1130   swi    "XOS_Module"
 1140   ldmvsfd (sp)!,{pc}   ; Memory claim failed
 1150   str    r2,[r12]      ; Store in w/s pointer
 1160   mov    r0,#0
 1170   mov    r1,#256/4     ; Loop for 256/4 words
 1180   .InitLoop
 1190   str    r0,[r2],#4    ; Zero workspace values
 1200   subs   r1,r1,#1
 1210   bne    InitLoop
 1220   .Reinitialise
 1230   ldr    r2,[r12]      ; Get w/s pointer back
 1240   mov    r0,#&40
 1250   strb   r0,[r2,#&47]  ; Set DriveReady
 1260   mov    r0,#0
 1270   cmp    r0,r0         ; Clear flags, etc
 1280   ldmfd  (sp)!,{pc}
 1290   :
 1300   :
 1310   .Finalise
 1320   stmfd  (sp)!,{link}
 1330   ldr    r3,[r12]      ; Get pointer to module's workspace
 1340   orrs   r3,r3,#0
 1350   beq    Finalised     ; No workspace (shouldn't ever get called this way)
 1360   :
 1370   ldr    r2,[r3,#&24]  ; IDE device 0 buffer
 1380   orrs   r2,r2,#0
 1390   movne  r0,#7
 1400   swine  "XOS_Module"  ; Release it if used
 1410   :
 1420   ldr    r2,[r3,#&28]  ; IDE device 0 pathname
 1430   orrs   r2,r2,#0
 1440   movne  r0,#7
 1450   swine  "XOS_Module"  ; Release it if used
 1460   :
 1470   ldr    r2,[r3,#&34]  ; IDE device 1 buffer
 1480   orrs   r2,r2,#0
 1490   movne  r0,#7
 1500   swine  "XOS_Module"  ; Release it if used
 1510   :
 1520   ldr    r2,[r3,#&38]  ; IDE device 1 pathname
 1530   orrs   r2,r2,#0
 1540   movne  r0,#7
 1550   swine  "XOS_Module"  ; Release it if used
 1560   :
 1570   ldr    r2,[r12]      ; Get pointer to module's workspace
 1580   mov    r0,#7
 1590   swi    "XOS_Module"  ; Release it
 1600   .Finalised
 1610   ldmfd  (sp)!,{pc}
 1620   :
 1630   :
 1640   .BBCIDE                 ; *BBCIDE <filename> - should have <device> parameter
 1650   stmfd  (sp)!,{r0-r5,link}
 1660                           ; r0=>parameters
 1670   ldr    r12,[r12]        ; Get address of workspace
 1680   stmfd  (sp)!,{r0}       ; Save pointer to parameters
 1690   ldr    r2,[r12,#&24]    ; Get address of file buffer
 1700   orrs   r2,r2,r2         ; Does buffer exist?
 1710   bne    BBCIDEBuffer
 1720   mov    r3,#512
 1730   mov    r0,#6
 1740   swi    "XOS_Module"     ; Claim space for file buffer
 1750   str    r2,[r12,#&24]    ; Store address of buffer
 1760   .BBCIDEBuffer
 1770   ldr    r2,[r12,#&28]    ; Get address of pathname
 1780   orrs   r2,r2,r2         ; Does pathname space exist?
 1790   bne    BBCIDEPathname
 1800   mov    r3,#256
 1810   mov    r0,#6
 1820   swi    "XOS_Module"     ; Claim space for pathname
 1830   str    r2,[r12,#&28]    ; Store address of pathname
 1840   .BBCIDEPathname
 1850   ldmfd  (sp)!,{r0}       ; Get pointer to parameters back
 1860   mov    r3,#0            ; Offset into name
 1870   .BBCIDELoop
 1880   ldrb   r1,[r0,r3]       ; Get character
 1890   strb   r1,[r2,r3]       ; Store character
 1900   cmp    r1,#ASC"!"       ; Found <ctrl> char?
 1910   bcc    BBCIDENameDone   ; Yes, stop
 1920   add    r3,r3,#1         ; Update index
 1930   cmp    r3,#255
 1940   bcc    BBCIDELoop       ; Loop while <256
 1950   .BBCIDENameDone
 1960   mov    r1,#13
 1970   strb   r1,[r2,r3]       ; Store terminating <cr>
 1980   :
 1990   ldrb   r0,[r2,#0]       ; Get first character
 2000   cmp    r0,#ASC"!"       ; Null filename?
 2010   movcc  r4,#0            ; Set size to zero
 2020   bcc    BBCIDENull       ; Jump to set size
 2030   mov    r0,#5            ; r0=ReadInfo
 2040   mov    r1,r2            ; r1=>filename
 2050   swi    "XOS_File"       ; Read file information
 2060   ands   r0,r0,#1         ; Is it a file?
 2070   moveq  r4,#0            ; Not a file - set length to zero
 2080   .BBCIDENull
 2090   str    r4,[r12,#&20]    ; Store size
 2100   mov    r4,#0
 2110   str    r4,[r12,#&2C]    ; Zero PTR and flags
 2120   ldmfd  (sp)!,{r0-r5,pc}
 2130   :
 2140   :
 2150   .BBCIDELoad             ; *BBCIDELoad <filename>
 2160   stmfd  (sp)!,{r0-r5,link}
 2170   ;ldr    r12,[r12]       ; Get address of workspace
 2180   ;add    r2,r12,#512     ; Point to variables
 2190   ;add    r2,r2,#20       ; Point to RAM address
 2200   ;ldr    r1,[r2]         ; Get RAM address
 2210   ;orrs   r1,r1,#0
 2220   ;beq    BBCIDENoRAM     ; No RAM to load to
 2230   ;mov    r3,#0           ; Load to r2
 2240   ;mov    r2,r1           ; r2=address to load to
 2250   ;mov    r1,r0           ; r1=>filename
 2260   ;mov    r0,#&FF         ; r0=LOAD
 2270   ;swi    "OS_File"       ; Load the specified file
 2280   ldmfd  (sp)!,{r0-r5,pc}
 2290   :
 2300   :
 2310   .BBCIDESave
 2320   stmfd  (sp)!,{r0-r5,link}
 2330   ;ldr    r12,[r12]       ; Get address of workspace
 2340   ;add    r2,r12,#512     ; Point to variables
 2350   ;add    r2,r2,#16       ; Point to RAM size
 2360   ;ldr    r3,[r2],#4      ; Set BBCIDE size
 2370   ;ldr    r1,[r2]         ; Get RAM address
 2380   ;orrs   r1,r1,#0
 2390   ;beq    BBCIDENoRAM     ; No RAM to load to
 2400   ;add    r5,r1,r3        ; r5=end address
 2410   ;mov    r4,r1           ; r4=start address
 2420   ;mov    r2,#&FD
 2430   ;orr    r2,r2,#&0F00    ; r2=&FFD - 'DATA'
 2440   ;mov    r1,r0           ; r1=>filename
 2450   ;mov    r0,#&0A         ; r0=SAVE as type
 2460   ;swi    "OS_File"       ; Save the specified file
 2470   ldmfd  (sp)!,{r0-r5,pc}
 2480   :
 2490   :
 2500   .BBCIDENoRAM
 2510   adr    r0,Error_NoRAM
 2520   swi    "OS_GenerateError"
 2530   ldmfd  (sp)!,{r0-r5,pc}
 2540   .Error_NoRAM
 2550   equd   &80AD0
 2560   equs   "No BBCIDE memory"
 2570   equb   0
 2580   align
 2590   :
 2600   :
 2610   .Service
 2620   ; In r0=mem[0]
 2630   ;    r1=Service_6502IN    - &80AD0
 2640   ;    r1=Service_6502OUT   - &80AD1
 2650   ;    r1=Service_6502Reset - &80AD2
 2660   ;    r2=port
 2670   ;    r3=value
 2680   ;    r4=Module base
 2690   ;
 2700   stmfd  (sp)!,{r1}       ; Save service call number
 2710   and    r1,r1,#&FF000    ; Check b12-b19
 2720   cmp    r1,#&80000       ; &80xxx ?
 2730   ldmfd  (sp)!,{r1}       ; Restore service call number
 2740   movne  pc,link          ; No -> exit unclaimed
 2750   :
 2760   stmfd  (sp)!,{r1}
 2770   and    r1,r1,#&FF0
 2780   cmp    r1,#&AD0         ; &80ADx ?
 2790   ldmfd  (sp)!,{r1}
 2800   movne  pc,link          ; No
 2810   :
 2820   stmfd  (sp)!,{r1}
 2830   and    r1,r1,#&F
 2840   cmp    r1,#&3           ; &80AD0..&80AD2 ?
 2850   ldmfd  (sp)!,{r1}
 2860   movcs  pc,link          ; No
 2870   :
 2880   stmfd  (sp)!,{r2}       ; Save port number
 2890   and    r2,r2,#&FF00     ; Lose bottom byte
 2900   cmp    r2,#&FC00        ; Port &FCxx ?
 2910   ldmfd  (sp)!,{r2}       ; Restore port number
 2920   movne  pc,link          ; No -> exit unclaimed
 2930   :
 2940   stmfd  (sp)!,{r2}       ; Save port number
 2950   and    r2,r2,#&F0       ; Lose top byte
 2960   cmp    r2,#&40          ; Port &FC4x ?
 2970   ldmfd  (sp)!,{r2}       ; Restore port number
 2980   movne  pc,link          ; No -> exit unclaimed
 2990   :
 3000   ldr    r12,[r12]        ; Get workspace address
 3010   stmfd  (sp)!,{r1}       ; Save service number
 3020   and    r1,r1,#&F        ; Check service number
 3030   cmp    r1,#&1           ; &80AD0 ?
 3040   bcc    Service_6502IN
 3050   beq    Service_6502OUT
 3060                           ; Fall through to Reset
 3070   :
 3080   .Service_6502Reset
 3090   ldmfd  (sp)!,{r1}       ; Restore call number, balance stack
 3100   ;stmfd (sp)!,{link}
 3110   ;ldmfd (sp)!,{link}
 3120   mov    pc,link          ; Don't claim
 3130   :
 3140   :
 3150   .Service_6502IN         ; Read from &FC4x
 3160   ldmfd  (sp)!,{r1}       ; Restore call number, balance stack
 3170   ; r0=z80mem[0]
 3180   ; r1=corruptable
 3190   ; r2=port number - corruptable
 3200   ; r3=returns Read value
 3210   ; r4=corruptable
 3220   ; stack balanced
 3230   ;
 3240   and    r2,r2,#&FF       ; r2=low byte
 3250   cmp    r2,#&40
 3260   beq    ReadIDEByteLow   ; Read from &FC40
 3270   cmp    r2,#&48
 3280   beq    ReadIDEByteHigh  ; Read from &FC48
 3290   ldrb   r3,[r12,r2]      ; Fetch byte from register
 3300   mov    r1,#0            ; Claim the call
 3310   mov    pc,link
 3320   :
 3330   .ReadIDEByteLow
 3340   .ReadIDEByteHigh
 3350   ldrb   r1,[r12,#&46]    ; Get IDEHead
 3360   ands   r1,r1,#&10       ; Device 1 selected?
 3370   movne  r1,#&00          ; Device not present
 3380   bne    WriteIDEStatus   ; Return with error set
 3390   ldr    r1,[r12,#&24]    ; Get buffer address
 3400   orrs   r1,r1,r1         ; Does a buffer exist?
 3410   beq    ReadByteEnd      ; No buffer, exit early
 3420   :
 3430   ldr    r1,[r12,#&2C]    ; Get current PTR offset
 3440   cmp    r1,#256          ; Within current buffer?
 3450   stmfd  (sp)!,{link}     ; Save link
 3460   blcs   UpdateLBA        ; Update LBA and PTR if past end of buffer
 3470   ldmfd (sp)!,{link}      ; Restore link
 3480   orrs   r1,r1,r1         ; Is PTR zero?
 3490   bne    ReadByteClean    ; No, buffer holds data
 3500   :
 3510   ldrb   r1,[r12,#&46]    ; Get head/device/LBA flag
 3520   ands   r1,r1,#&40       ; Get LBA flag
 3530   bne    ReadLBA          ; Jump to calculate file PTR with LBA
 3540   ldrb   r1,[r12,#&43]    ; Get sector
 3550   sub    r1,r1,#1
 3560   and    r0,r1,#63        ; 64 sectors per track
 3570   ldrb   r1,[r12,#&46]    ; Get head
 3580   and    r1,r1,#3         ; 4 heads per track
 3590   orr    r0,r0,r1,lsl #6  ; Merge with sector
 3600   ldr    r1,[r12,#&44]    ; Get cylinder
 3610   orr    r0,r0,r1,lsl #8  ; Merge into head+sector
 3620   mov    r0,r0,lsl #8     ; Multipy by 256 to get PTR required
 3630   b      ReadCHS
 3640   .ReadLBA
 3650   ldr    r1,[r12,#&40]    ; Get LBA b0-b7 in top byte
 3660   and    r1,r1,#&FF000000 ; LBA b0-b7 in b24-b31
 3670   ldr    r0,[r12,#&44]    ; LBA b8-b27 in b0-b19
 3680   mov    r0,r0,lsl #16    ; LBA b8-b23 in b16-b31
 3690   orr    r0,r0,r1,lsr #16 ; r0=<LBA b8-b23>+<LBA b0-b7>+<&00>
 3700                           ; r0=file PTR required
 3710   .ReadCHS
 3720   ; Should check here for double-spacing
 3730   ldr    r1,[r12,#&20]    ; Drive size
 3740   cmp    r0,r1            ; Reading from past end of drive?
 3750   movcs  r1,#&41          ; If past end of drive, set error
 3760   strcsb r1,[r12,#&47]
 3770   movcs  r1,#&10          ; Error is SectorNotFound
 3780   strcsb r1,[r12,#&41]
 3790   bcs    ReadByteEnd      ; Exit early with error
 3800   ldr    r1,[r12,#&28]    ; Point to pathname
 3810   ldrb   r2,[r1]          ; Get start of pathname
 3820   cmp    r2,#ASC"!"
 3830   movcc  r1,#&41          ; No pathname, set error
 3840   strccb r1,[r12,#&47]
 3850   movcc  r1,#&10          ; Error is SectorNotFound
 3860   strccb r1,[r12,#&41]
 3870   bcc    ReadByteEnd      ; No pathname, exit early
 3880   :
 3890   ; r0=file PTR
 3900   ; r1=>filename
 3910   ; r2=spare
 3920   ; r3=byte read
 3930   ; r4=spare
 3940   stmfd  (sp)!,{link}     ; Save link as we're going to use SWIs
 3950   mov    r4,r0            ; PTR to read from
 3960   mov    r0,#&40
 3970   swi    "XOS_Find"       ; Open for input
 3980   mov    r3,#256          ; 256 bytes to read
 3990   ldr    r2,[r12,#&24]    ; r2=>buffer
 4000   mov    r1,r0            ; r1=handle
 4010   mov    r0,#3            ; Read using specified PTR
 4020   swi    "XOS_GBPB"       ; Read to buffer
 4030   mov    r0,#0
 4040   swi    "XOS_Find"       ; Close file
 4050   ldmfd  (sp)!,{link}     ; Restore link
 4060   :
 4070   .ReadByteClean
 4080   ldr    r1,[r12,#&24]    ; Point to buffer
 4090   ldr    r0,[r12,#&2C]    ; Get current PTR offset
 4100   ldrb   r3,[r1,r0]       ; Get byte from buffer
 4110   add    r0,r0,#1         ; Increment PTR offset
 4120   str    r0,[r12,#&2C]    ; Store updated PTR offset
 4130   .ReadByteEnd
 4140   mov    r1,#0            ; Claim the call
 4150   mov    pc,link
 4160   :
 4170   :
 4180   .Service_6502OUT        ; Write to &FC4x
 4190   ldmfd  (sp)!,{r1}       ; Restore call number, balance stack
 4200   ; r0=z80mem[0]
 4210   ; r1=corruptable
 4220   ; r2=port number - corruptable
 4230   ; r3=Write value
 4240   ; r4=corruptable
 4250   ; stack balanced
 4260   ;
 4270   and    r2,r2,#&FF       ; r2=low byte
 4280   cmp    r2,#&40
 4290   beq    WriteIDEByteLow  ; Write to &FC40
 4300   cmp    r2,#&47
 4310   beq    WriteIDECommand  ; Write to &FC47
 4320   cmp    r2,#&48
 4330   beq    WriteIDEByteHigh ; Write to &FC48
 4340   strb   r3,[r12,r2]      ; Store byte to register
 4350   mov    r1,#0            ; Claim the call
 4360   mov    pc,link
 4370   :
 4380   .WriteIDECommand
 4390   strb   r3,[r12,#&40]    ; Store current command
 4400   mov    r1,#0
 4410   str    r1,[r12,#&2C]    ; Clear current buffer
 4420   mov    r1,#&48          ; Set DriveReady+DataReady
 4430   .WriteIDEStatus
 4440   strb   r1,[r12,#&47]    ; Set IDEstatus
 4450   mov    r1,#0
 4460   mov    pc,link          ; Claim the call
 4470   ;
 4480   .WriteIDEByteLow
 4490   .WriteIDEByteHigh
 4500   ldrb   r1,[r12,#&46]    ; Get IDEHead
 4510   ands   r1,r1,#&10       ; Device 1 selected?
 4520   movne  r1,#&00          ; Device not present
 4530   bne    WriteIDEStatus   ; Return with error set
 4540   ldr    r1,[r12,#&24]    ; Get buffer address
 4550   orrs   r1,r1,r1         ; Does a buffer exist?
 4560   beq    WriteByteEnd     ; No buffer, exit early
 4570   :
 4580   ldr    r1,[r12,#&2C]    ; Get current PTR offset
 4590   cmp    r1,#256          ; Is buffer full?
 4600   stmfd  (sp)!,{link}
 4610   blcs   UpdateLBA        ; Buffer overflowed, move to next sector
 4620   ldmfd  (sp)!,{link}
 4630   :
 4640   .WriteByteClean
 4650   ldr    r1,[r12,#&24]    ; Point to buffer
 4660   ldr    r0,[r12,#&2C]    ; Get current PTR offset
 4670   strb   r3,[r1,r0]       ; Put byte into buffer
 4680   add    r0,r0,#1         ; Increment PTR offset
 4690   str    r0,[r12,#&2C]    ; Store updated PTR offset
 4700   cmp    r0,#256          ; Is buffer full?
 4710   bcc    WriteByteEnd     ; Buffer not full, exit
 4720   :
 4730   ldrb   r1,[r12,#&46]    ; Get head/device/LBA flag
 4740   ands   r1,r1,#&40       ; Get LBA flag
 4750   bne    WriteLBA         ; Jump to calculate file PTR with LBA
 4760   ldrb   r1,[r12,#&43]    ; Get sector
 4770   sub    r1,r1,#1
 4780   and    r0,r1,#63        ; 64 sectors per track
 4790   ldrb   r1,[r12,#&46]    ; Get head
 4800   and    r1,r1,#3         ; 4 heads per track
 4810   orr    r0,r0,r1,lsl #6  ; Merge with sector
 4820   ldr    r1,[r12,#&44]    ; Get cylinder
 4830   orr    r0,r0,r1,lsl #8  ; Merge into head+sector
 4840   mov    r0,r0,lsl #8     ; Multipy by 256 to get PTR required
 4850   b      WriteCHS
 4860   .WriteLBA
 4870   ldr    r1,[r12,#&40]    ; Get LBA b0-b7 in top byte
 4880   and    r1,r1,#&FF000000 ; LBA b0-b7 in b24-b31
 4890   ldr    r0,[r12,#&44]    ; LBA b8-b27 in b0-b19
 4900   mov    r0,r0,lsl #16    ; LBA b8-b23 in b16-b31
 4910   orr    r0,r0,r1,lsr #16 ; r0=<LBA b8-b23>+<LBA b0-b7>+<&00>
 4920                           ; r0=file PTR required
 4930   .WriteCHS
 4940   ldr    r1,[r12,#&20]    ; Drive size
 4950   cmp    r0,r1            ; Reading from past end of drive?
 4960   movcs  r1,#&41          ; If past end of drive, set error
 4970   strcsb r1,[r12,#&47]
 4980   movcs  r1,#&10          ; Error is SectorNotFound
 4990   strcsb r1,[r12,#&41]
 5000   bcs    WriteByteEnd     ; If past end of drive, exit early
 5010   ldr    r1,[r12,#&28]    ; Point to pathname
 5020   ldrb   r2,[r1]          ; Get start of pathname
 5030   cmp    r2,#ASC"!"
 5040   movcc  r1,#&41          ; No pathname, set error
 5050   strccb r1,[r12,#&47]
 5060   movcc  r1,#&10          ; Error is SectorNotFound
 5070   strccb r1,[r12,#&41]
 5080   bcc    WriteByteEnd     ; No pathname, exit early
 5090   :
 5100   ; r0=file PTR
 5110   ; r1=>filename
 5120   ; r2=spare
 5130   ; r3=byte to write, now spare
 5140   ; r4=spare
 5150   stmfd  (sp)!,{link}     ; Save link as we're going to use SWIs
 5160   mov    r4,r0            ; PTR to write to
 5170   mov    r0,#&C0
 5180   swi    "XOS_Find"       ; Open for update
 5190   mov    r3,#256          ; 256 bytes to write
 5200   ldr    r2,[r12,#&24]    ; r2=>buffer
 5210   mov    r1,r0            ; r1=handle
 5220   mov    r0,#1            ; Write using specified PTR
 5230   swi    "XOS_GBPB"       ; Write from buffer
 5240   mov    r0,#0
 5250   swi    "XOS_Find"       ; Close file
 5260   ldmfd  (sp)!,{link}     ; Restore link
 5270   :
 5280   .WriteByteEnd
 5290   mov    r1,#0            ; Claim the call
 5300   mov    pc,link
 5310   :
 5320   .UpdateLBA              ; LBA=LBA+1
 5330   ldr    r1,[r12,#&40]
 5340   sub    r1,r1,#&00010000 ; Count=Count-1
 5350   adds   r1,r1,#&01000000 ; LBAb0-b7=LBAb0-b7+1
 5360   str    r1,[r12,#&43]
 5370   ldrb   r1,[r12,#&44]
 5380   adc    r1,r1,#0         ; LBAb8-b27=LBAb8-b27+cy
 5390   str    r1,[r12,#&44]    ; **WARNING** Overflows into drive
 5400   mov    r1,#0
 5410   str    r1,[r12,#&2C]    ; Reset PTR offset to zero
 5420   mov    pc,link
 5430   :
 5440   ALIGN
 5450 ]NEXT
 5460 OSCLI"SAVE BBCIDE "+STR$~mcode%+" "+STR$~O%
 5470 *SetType BBCIDE Module
 5480 *Stamp BBCIDE
 5490 END