10 REM > OswFE/src
   20 REM Source for OSWORD &FE used by Z80Tube 2
   30 REM BUGS
   40 REM There is a lot of redundancy and unused code.
   50 REM Checks for &FFFExxxx for screen memory, but never acts on it.
   60 REM Master version doesn't use correct DRVSEL bitmap.
   70 REM Master version uses wrong address for DRVSEL and FDC.
   80 REM Master version reads drive speed from KBD links instead of NVRAM.
   90 :
  100 REM OSWORD &FE does FM floppy disk access with 1770 controller
  110 REM  XY?0 = &12 inward block length
  120 REM  XY?1 = &03 outward block length
  130 REM   Followed by OSWORD &72 SCSI command block:
  140 REM  XY?2 = returned result
  150 REM  XY!3 = addr
  160 REM  XY?7 = command
  170 REM  XY?8 = drive+sector b16-b20
  180 REM  XY?9 = sector b8-b15
  190 REM  XY?10= sector b0-b7
  200 REM  XY?11= sector count - what does &00 mean?
  210 REM  XY?12= drive reset flags, b7=drive 0, b6=drive 1, etc.
  220 REM  XY?13= drive settings, XY?13=drive 0, XY?14=drive 1, etc.
  230 :
  240 OS_CLI=&FFF7:OSBYTE=&FFF4:OSWORD=&FFF1:OSWRCH=&FFEE
  250 OSWRCR=&FFEC:OSNEWL=&FFE7:OSASCI=&FFE3:OSRDCH=&FFE0
  260 USERV=&200
  270 :
  280 ctrl=&80:addr=&82
  290 :
  300 REM &FE80 Drive Control
  310 REM   0 0 ~RESET NMI DDEN SIDE DS1 DS0
  320 REM &FE84 Command/Status
  330 REM   MOTOR WPROT SPIN SNF CRC TRK0 IDX BSY
  340 REM &FE85 Track
  350 REM &FE86 Sector
  360 REM &FE87 Data
  370 :
  380 run%=&FFFF2A00:load%=&FFFF2A00:fname$="OswFE"
  390 DIM mcode% &700
  400 FOR P=0 TO 1
  410   P%=run%:O%=mcode%
  420   [OPT P*3+4
  430   \ OSWORD &FE entry
  440   \ ----------------
  450   .L2A00
  460   INX:INX              :\ Step past header bytes
  470   :                    :\ *BUG* will fail if &xxFE or &xxFF
  480   STX &80:STY &81      :\ Point to control block
  490   LDA #&80:STA L2EFB   :\ Set Tube not being used
  500   JMP L2A64            :\ Jump into code
  510   :
  520   .L2A0E
  530   RTS                  :\ Never called
  540   :
  550   .L2A0F
  560   JSR L2C7D            :\ 2A0F 20 7D 2C     },
  570   LDX #&00:JSR L2A59   :\ Write count in &A3 to track in &FE84 (looks wrong)
  580   INX:JSR L2A59        :\ Write sector in &A4 to sector in &FE85
  590   INX:JSR L2A59        :\ Write track in &A5 to data in &FE86 (looks wrong)
  600   CMP &A3              :\ Compare with count in &A3
  610   BEQ L2A3C            :\ 2A21 F0 19       p.
  620   LDA &A5              :\ Get track from &A5
  630   BNE L2A2A            :\ 2A25 D0 03       P.
  640   JMP L2C91            :\ 2A27 4C 91 2C    L.,
  650   :
  660   .L2A2A
  670   ROR L2EFA            :\ 2A2A 6E FA 2E    nz.
  680   SEC                  :\ 2A2D 38          8
  690   ROL L2EFA            :\ 2A2E 2E FA 2E    .z.
  700   LDA #&14             :\ 2A31 A9 14       ).
  710   ORA &0D5C:STA &FE84  :\ 2A36 8D 84 FE    ..~
  720   JSR L2C18            :\ Wait until command completed
  730   .L2A3C
  740   LDA &A5              :\ 2A3C A5 A5       %%
  750   STA &A3              :\ 2A3E 85 A3       .#
  760   LDA &A1              :\ 2A40 A5 A1       %!
  770   ROR A                :\ 2A42 6A          j
  780   BCC L2A48            :\ 2A43 90 03       ..
  790   .L2A45
  800   JMP L2EA2            :\ Release and return
  810   
  820   .L2A48
  830   BIT &A1              :\ 2A48 24 A1       $!
  840   BVS L2A56            :\ 2A4A 70 0A       p.
  850   LDY #&05             :\ 2A4C A0 05        .
  860   LDA (&80),Y          :\ 2A4E B1 80       1.
  870   CMP #&0B             :\ 2A50 C9 0B       I.
  880   BNE L2A56            :\ 2A52 D0 02       P.
  890   BEQ L2A45            :\ 2A54 F0 EF       po
  900   .L2A56
  910   JSR L2C7D            :\ Clear &A2 bit 0 - NMI not completed
  920   :
  930   \ Write to FDC register and ensure it holds
  940   .L2A59
  950   LDA &A3,X:STA &FE85,X  :\ Write to register
  960   CMP &FE85,X:BNE L2A59  :\ Loop until it stays
  970   RTS
  980   :
  990   \ OSWORD &FE entry
 1000   \ ================
 1010   \ (&80)=>control block +2
 1020   .L2A64
 1030   TSX:STX L2EF4        :\ Save stack pointer
 1040   LDA #&10:STA L2EF1   :\ Prepare action=&10
 1050   JSR L2A75            :\ Prepare for the operation, seek 0 if needed
 1060   JSR L2CAA            :\ Do the actual operation, returns with EQ
 1070   BEQ L2A45            :\ Jump to release and return result
 1080   :
 1090   \ (&80),Y
 1100   \ Followed by OSWORD &72 SCSI command block:
 1110   \  &00  returned result
 1120   \  &01  addr b0-b7
 1130   \  &02  addr b8-b15
 1140   \  &03  addr b16-b23
 1150   \  &04  addr b24-b31
 1160   \  &05  command
 1170   \  &06  drive+sector b16-b20
 1180   \  &07  sector b8-b15
 1190   \  &08  sector b0-b7
 1200   \  &09  sector count
 1210   \  &0A  restore to track zero before starting, b7=drive 0, b6=drive 1
 1220   \  &0B  drive 0 setting
 1230   \  &0C  drive 1 setting
 1240   \  &0D
 1250   \  &0E
 1260   \  &0F
 1270   .L2A75
 1280   LDA #&00:STA L2EF3            :\ Set result to &00
 1290   LDY #&01:LDA (&80),Y:STA &82  :\ Get address from control block
 1300   INY:LDA (&80),Y:STA &83       :\ &82/&82 never used
 1310   INY:LDA (&80),Y:TAX           :\ X=&..XX....
 1320   INY:LDA (&80),Y               :\ A=&XX......
 1330   INX:BEQ L2A92                 :\ address=&xxFFxxxx, check I/O
 1340   INX:BNE L2A96                 :\ address<>&xxFExxxx, skip past
 1350   .L2A92
 1360   CMP #&FF:BEQ L2A99            :\ Check for &FFxxxxxx
 1370   :
 1380   \ Not &FFFFxxxx or &FFFExxxx
 1390   .L2A96
 1400   JSR L2B25            :\ Claim Tube
 1410   .L2A99
 1420   LDY #&05:LDA (&80),Y :\ Get command
 1430   CMP #&08:BEQ L2AB1   :\ &08=Read
 1440   CMP #&0A:BEQ L2AB8   :\ &0A=Write
 1450   CMP #&0B:BEQ L2AB1   :\ &0B=Seek/Park
 1460   LDA #&67:STA L2EF3   :\ Result=&67 - Unsupported FDD command
 1470   JMP L2EA2            :\ Release and return
 1480   :
 1490   .L2AB1
 1500   ROL L2EF1:SEC:ROR L2EF1  :\ Read/Seek, set action=&11
 1510   .L2AB8
 1520   JSR L2AE9            :\ Set up disk controller speeds
 1530   JSR L2AC1            :\ Set up NMIs
 1540   JMP L2DEE            :\ Jump to perform the action
 1550   :
 1560   .L2AC1
 1570   JSR L2B0F            :\ Claim NMIs
 1580   LDA L2EF6:STA &0D56  :\ Disk speed &00 or &02
 1590   LDA L2EF5:STA &0D5C  :\ Disk speed &00 or &03
 1600   LDA #&00
 1610   STA &A0:STA &A2      :\ Clear result and NMI flags
 1620   LDA L2EF1:ORA #&20   :\ Set Action to &30 or &31
 1630   STA L2EF1:STA &A1
 1640   LDA L2EFB:STA &0D5D  :\ Tube flag &80 or &81
 1650   JMP L2B4E            :\ Initialse NMI code
 1660   :
 1670   .L2AE9
 1680   LDA #&00
 1690   STA L2EF6:STA L2EF5  :\ Set speed controls to &00
 1700   LDA #&FF:LDX #&00
 1710   TAY:JSR OSBYTE       :\ Read disk speed from kbd options
 1720   TXA:PHA
 1730   AND #&20:BEQ L2B04
 1740   LDA #&03:STA L2EF5   :\ Speed bit5 set, set to &03
 1750   .L2B04
 1760   PLA:AND #&10:BEQ L2B0E
 1770   LDA #&02:STA L2EF6   :\ Speed bit4 set, set to &02
 1780   .L2B0E
 1790   RTS
 1800   :
 1810   \ Claim NMIs
 1820   .L2B0F
 1830   LDA #&8F:LDX #&0C    :\ Service &0C - Claim NMIs
 1840   LDY #&FF
 1850   .L2B15
 1860   JSR OSBYTE           :\ Make service call
 1870   STY L2EF2            :\ Save previous NMI owner
 1880   RTS
 1890   :
 1900   \ Release NMIs
 1910   .L2B1C
 1920   LDY L2EF2            :\ Get previous NMI owner
 1930   LDA #&8F:LDX #&0B    :\ Service call &0B - Release NMIs
 1940   BNE L2B15
 1950   :
 1960   \ Claim Tube
 1970   .L2B25
 1980   LDY #&04                :\ Prepare to copy 4 bytes
 1990   BIT L2EFB:BPL L2B42     :\ If Tube already claimed, exit
 2000   .L2B2C
 2010   LDA (&80),Y:STA L2EFB,Y :\ Copy transfer address
 2020   DEY:BNE L2B2C
 2030   ROR L2EFB:SEC:ROL L2EFB :\ Set flag to &81
 2040   .L2B3B
 2050   LDA #&C3:JSR &0406      :\ Claim with ID=&03
 2060   BCC L2B3B               :\ Loop until claimed
 2070   .L2B42
 2080   RTS
 2090   :
 2100   .L2B43
 2110   ROR L2EFB:BCC L2B4D  :\ Tube not being used, return
 2120   LDA #&83:JSR &0406   :\ Release Tube with ID=3
 2130   .L2B4D
 2140   RTS
 2150   :
 2160   \ Copy NMI code to NMI area
 2170   \ -------------------------
 2180   .L2B4E
 2190   LDY #&48
 2200   .L2B50
 2210   LDA L2BCF,Y:STA &0D00,Y  :\ Copy NMI code
 2220   DEY:BPL L2B50
 2230   LDY #&02
 2240   .L2B5B
 2250   LDA (&80),Y:STA &0D0D,Y :\ Copy I/O address to NMI routine
 2260   DEY:BNE L2B5B
 2270   BIT &A1:BMI L2B6C
 2280   LDA #&5F:STA &0D05
 2290   .L2B6C
 2300   LDA L2EFB                :\ Get IO/Tube flag
 2310   ROR A:BCC L2B7D          :\ Initialise I/O transder
 2320   LDA &A1:AND #&FD:STA &A1
 2330   JSR L2B86:BMI L2B80      :\ Initialise Tube transfer
 2340   :
 2350   .L2B7D
 2360   JSR L2BB5            :\ Initialise I/O transfer
 2370   .L2B80
 2380   LDA &F4:STA &0D34    :\ Set ROM to page in
 2390   RTS
 2400   :
 2410   \ Start Tube transfer
 2420   .L2B86
 2430   LDA &A1:ROL A        :\ Get action
 2440   LDA #&00:ROL A       :\ Convert into Tube action
 2450   LDY #&2E:LDX #&FC    :\ XY=>transfer address
 2460   JSR &0406
 2470   LDA &A1              :\ Get action
 2480   AND #&10:BEQ L2BA8   :\ No transfer to happen
 2490   BIT &A1:BMI L2BA9
 2500   LDY #&07
 2510   .L2B9F
 2520   LDA L2C43,Y:STA &0D0A,Y :\ Copy Tube code to NMI area
 2530   DEY:BPL L2B9F
 2540   .L2BA8
 2550   RTS
 2560   :
 2570   .L2BA9
 2580   LDY #&07
 2590   .L2BAB
 2600   LDA L2C4B,Y:STA &0D0A,Y :\ Copy Tube code to NMI area
 2610   DEY:BPL L2BAB:RTS
 2620   :
 2630   .L2BB5
 2640   BIT &A1:BMI L2BCE       :\ I/O LOAD, nothing to change
 2650   LDY #&0D
 2660   .L2BBB
 2670   LDA L2C35,Y:STA &0D0A,Y :\ Copy I/O SAVE code to NMI area
 2680   DEY:BPL L2BBB
 2690   LDY #&02
 2700   .L2BC6
 2710   LDA (&80),Y:STA &0D0A,Y :\ Copy transfer address to NMI area
 2720   DEY:BNE L2BC6
 2730   .L2BCE
 2740   RTS
 2750   :
 2760   \ FDC NMI routine, copied to NMI space at &0D00
 2770   \ =============================================
 2780   \ Defaults to IO LOAD code
 2790   .L2BCF
 2800   .L0D00
 2810   PHA
 2820   LDA &FE84:AND #&1F   :\ Get FDC status, keep error bits
 2830   CMP #&03:BNE L0D1A   :\ If not DRQ+BSY, completed or error
 2840   .L0D0A
 2850   LDA &FE87:STA &FFFF  :\ Fetch byte to memory
 2860   INC &0D0E            :\ Update I/O address
 2870   BNE L0D18:INC &0D0F
 2880   .L0D18
 2890   PLA:RTI              :\ Return from NMI
 2900   :
 2910   \ FDC controller error or completion
 2920   .L0D1A
 2930   AND #&58:BEQ L0D2C   :\ Skip if no error bits set, must be completion
 2940   STA &A0              :\ Store as result
 2950   \ &08 CRC error in data
 2960   \ &10 Sector not found
 2970   \ &18 CRC error in ID
 2980   \ &40 Write protected
 2990   ROR &A1:SEC:ROL &A1  :\ Set bit 0, NMI error
 3000   .L0D25
 3010   ROR &A2:SEC:ROL &A2  :\ Set bit 0, NMI completed
 3020   PLA:RTI              :\ Return from NMI
 3030   :
 3040   \ Not an error, must be NMI completed
 3050   .L0D2C
 3060   BIT &A2:BVC L0D25    :\ If bit6 set, exit completed
 3070   LDA &F4:PHA          :\ Save current ROM
 3080   LDA #&00             :\ ROM number
 3090   STA &F4:STA &FE30    :\ Page in ROM (not needed, we are in RAM)
 3100   TXA:PHA:JSR L2D59
 3110   PLA:TAX:PLA
 3120   STA &F4:STA &FE30    :\ Restore ROM
 3130   PLA:RTI              :\ Return from NMI
 3140   \ End of NMI code
 3150   \ ===============
 3160   :
 3170   \ Wait until &A2.bit 0 is set indicating NMI completed
 3180   \ If &0D5D.bit4 set, allow Escape to abort
 3190   .L2C18
 3200   LDA &A2:ROR A:BCC L2C1E :\ Jump forward
 3210   RTS                  :\ &A2 changed, exit
 3220   .L2C1E
 3230   LDA &0D5D            :\ Get Escape-allowed flag
 3240   AND #&10:BEQ L2C18   :\ &0%d%.b4=0, Escape not allowed, loop back
 3250   BIT &FF:BPL L2C18    :\ Loop back if no Escape
 3260   LDA #&00:STA &FE80   :\ Reset 1770
 3270   LDA #&6F:STA &A0     :\ Result=&7F - Aborted
 3280   JMP L2EA2            :\ Release and return
 3290   :
 3300   \ Copied to NMI area for I/O SAVE
 3310   .L2C35
 3320   LDA &FFFF:STA &FE87  :\ Copy byte from memory to disk
 3330   INC &0D0B            :\ Update embedded address
 3340   BNE L2C43:INC &0D0C
 3350   :
 3360   \ Copied to NMI area for Tube SAVE
 3370   .L2C43
 3380   LDA &FEE5:STA &FE87  :\ Copy byte C->H
 3390   BCS L2C51            :\ Skip past I/O address update
 3400   :
 3410   \ Copied to NMI area for Tube LOAD
 3420   .L2C4B
 3430   LDA &FE87:STA &FEE5  :\ Copy byte H->C
 3440   .L2C51
 3450   BCS L2C59            :\ Skip past I/O address update
 3460   :
 3470   .L2C53
 3480   BIT &A1:BMI L2C64    :\ 2C55 30 0D       0.
 3490   LDA &A3              :\ 2C57 A5 A3       %#
 3500   .L2C59
 3510   CMP #&14             :\ If <&14, convert to WriteSector
 3520   LDA #&A0:BCC L2C66   :\ CMS=WriteSector
 3530   ORA &0D56:BNE L2C66  :\ Otherwise, CMD=Seek+speed
 3540   :
 3550   .L2C64
 3560   LDA #&80             :\ CMD=ReadSector
 3570   .L2C66
 3580   STA &A6:JSR L2C7D    :\ Clear &A6 bit 0 - NMI not completed
 3590   LDA &A6:JSR L2C9E    :\ If &2EFA.b0 set, set 'e' in CMD
 3600   STA &FE84:RTS        :\ Write FDC command
 3610   :
 3620   \ Select side 2
 3630   \ -------------
 3640   .L2C74
 3650   LDA &0D5E:ORA #&04   :\ Update DRVSEL with SIDE=1
 3660   STA &0D5E:RTS
 3670   :
 3680   .L2C7D
 3690   ROR &A2:CLC:ROL &A2:RTS  :\ Clear bit 0 - NMI not completed
 3700   :
 3710   .L2C83
 3720   LDA &A2:AND #&F7:STA &A2 :\ Clear bit 3 -
 3730   RTS
 3740   :
 3750   .L2C8A
 3760   LDA &A2:AND #&FD:STA &A2 :\ Clear bit 1 -
 3770   RTS
 3780   :
 3790   .L2C91
 3800   LDA #&00:STA &A3     :\ Set to 0
 3810   ORA &0D5C:STA &FE84  :\ Do 'Restore', head=on, verify=off
 3820   JMP L2C18            :\ Wait until completed or Abort
 3830   :
 3840   .L2C9E
 3850   ROR L2EFA            :\ 2C9E 6E FA 2E    nz.
 3860   BCC L2CA6            :\ 2CA1 90 03       ..
 3870   ORA #&04             :\ 2CA3 09 04       ..
 3880   CLC                  :\ 2CA5 18          .
 3890   .L2CA6
 3900   ROL L2EFA            :\ 2CA6 2E FA 2E    .z.
 3910   RTS                  :\ 2CA9 60          `
 3920   :
 3930   \ Do the actual disk operation
 3940   \ ----------------------------
 3950   .L2CAA
 3960   JSR L2A0F                :\ Write &A3-&A5 to FE85-&FE87
 3970   LDA &A2:ORA #&40:STA &A2 :\ Set bit6
 3980   LDY #&07
 3990   LDA (&80),Y:STA &0D58    :\ Get sector b8-b15
 4000   INY:LDA (&80),Y          :\ Get sector b0-b7
 4010   INY:CLC:ADC (&80),Y      :\ (sector b0-b7)+count
 4020   STA &0D59
 4030   BCC L2CC9:INC &0D58      :\ Increment carry
 4040   .L2CC9
 4050   \ &0D58/&0D59=sector number after last sector, sector+count
 4060   :
 4070   LDA &0D58:TAX        :\ X=sectorend b8-b15
 4080   LDA &0D59            :\ A=sectorend b0-b7
 4090   LDY #&FF:JSR L2E96   :\ DIV/MOD10, Y=track, A=sector
 4100   CMP #&00:BNE L2CDB   :\ Not sector 0, not start of a track
 4110   LDA #&0A             :\ Use sector 10 as end sector
 4120   .L2CDB
 4130   \ Y=end track, A=end sector with &00 converted to &0A
 4140   :
 4150   LDY #&09:SEC:SBC (&80),Y  :\ endsector-count
 4160   BCS L2CFF                 :\ No overflow, within one track
 4170   LDA #&0A:SEC:SBC &A4      :\ 10-secnum = seccount
 4180   STA &0D58                 :\ Store as seccount for this track
 4190   LDA (&80),Y:SEC:SBC &0D58 :\ count - seccount
 4200   LDX #&00                  :\ X=0, A=sectount
 4210   LDY #&FF:JSR L2E96        :\ DIV/MOD10, Y=track, A=sector
 4220   STY &0D57:STA &0D59       :\ Y=tracks, A=sector
 4230   BPL L2D10                 :\ Jump forward to continue
 4240   :
 4250   .L2CFF
 4260   LDY #&09:LDA (&80),Y:STA &0D58 :\ sector count
 4270   LDA #&FF:STA &0D57
 4280   LDA #&00:STA &0D59
 4290   :
 4300   .L2D10
 4310   LDA #&00:STA &0D5A
 4320   INC &0D57            :\ Incr. track count
 4330   DEC &0D58            :\ Decr. sec. count
 4340   LDX #&01:JSR L2A59   :\ Write sector in &A4 to sector in &FE86
 4350   JSR L2C53            :\ Write read/write/seek command to FDC
 4360   .L2D23
 4370   JSR L2C18            :\ Wait until command completes
 4380   LDA &A2
 4390   AND #&02:BEQ L2D3E   :\ &A2 bit 1 clear, skip...
 4400   JSR L2C7D            :\ Clear &A2 bit 0 - NMI not completed
 4410   JSR L2C8A            :\ Clear &A2 bit 1
 4420   LDA #&54             :\ &54=StepIn+update+verify
 4430   ORA &0D5C:STA &FE84  :\ Write FDC command with step speed
 4440   INC &A3:BNE L2D23    :\ Incr. track, loop back to do another
 4450   :
 4460   .L2D3E
 4470   LDA &A2
 4480   AND #&08:BEQ L2D73   :\ Finished, exit
 4490   JSR L2C7D            :\ Clear &A2 bit 0 - NMI not completed
 4500   JSR L2C83            :\ Clear &A2 bit 3
 4510   INC &A3              :\ Incr. track
 4520   JSR L2C74            :\ Select SIDE=1
 4530   LDA #&04             :\ &04=Restore+verify
 4540   ORA &0D5C:STA &FE84  :\ Restore to track zero
 4550   BPL L2D23            :\ Loop back for more
 4560   :
 4570   \ Called here from NMI code, operation completed
 4580   \ Check various things, and increment to next sector
 4590   .L2D59
 4600   JSR L2C7D            :\ Clear &A2 bit 0 - NMI not completed
 4610   JSR L2D74            :\ Update track/sector/etc
 4620   TXA:BNE L2D68        :\ Not completed, write FDC command
 4630   ROR &A2:SEC:ROL &A2  :\ Set &A2 bit 0 - NMI completed
 4640   RTS
 4650   :
 4660   .L2D68
 4670   JSR L2C8A            :\ Clear bit 1
 4680   LDA &A6:JSR L2C9E    :\ Get FDC command, set bit 4 if needed
 4690   STA &FE84            :\ Write command to FDC
 4700   .L2D73
 4710   RTS
 4720   :
 4730   .L2D74
 4740   LDA &0D58:BNE L2DDD  :\ endsector not zero, jump to...
 4750   LDA &0D57:BNE L2D8D  :\ trackcount<>0, update track
 4760   LDA &0D59:BNE L2D87  :\ sectorcount<>0, update sector
 4770   LDX #&00:BEQ L2DED   :\ All done, return with X=&00
 4780   :
 4790   .L2D87
 4800   DEC &0D59            :\ Decr. number of sectors
 4810   JMP L2DE0            :\ Write incremented sectornumber to FDC
 4820   :
 4830   .L2D8D
 4840   LDA &0D5A:BNE L2DD7            :\ 2D90 D0 45       PE
 4850   ROR L2EFA:SEC:ROL L2EFA
 4860   LDA &FE85            :\ Get current track from FDC
 4870   CMP #&4F:BCC L2DBF   :\ <track79, skip
 4880   LDA &0D5E            :\ Get drive control
 4890   AND #&04:BEQ L2DAC   :\ If side 0, jump to step to side 1
 4900   LDX #&00:JMP L2DE2   :\ At end of disk, jump to return X=&00, done
 4910   :
 4920   .L2DAC
 4930   LDA #&FF:STA &A3
 4940   JSR L2C74            :\ Select SIDE=1
 4950   LDA &0D5E:STA &FE80  :\ Write updated drive control
 4960   LDA &A2:ORA #&08     :\ Set bit 3 -
 4970   BNE L2DC3
 4980   :
 4990   .L2DBF
 5000   LDA &A2:ORA #&02     :\ Set bit 1 -
 5010   .L2DC3
 5020   STA &A2              :\ Update flags
 5030   DEC &0D57:BEQ L2DCF  :\ Decrement
 5040   LDA #&0A:STA &0D5A   :\ Track length = 10 (?)
 5050   .L2DCF
 5060   LDA #&FE:STA &A4
 5070   LDX #&00:BEQ L2DE2   :\ jump to return X=&00, done
 5080   :
 5090   .L2DD7
 5100   DEC &0D5A            :\ 2DD7 CE 5A 0D    NZ.
 5110   JMP L2DE0            :\ 2DDA 4C E0 2D    L`-
 5120   :
 5130   .L2DDD
 5140   DEC &0D58            :\ 2DDD CE 58 0D    NX.
 5150   .L2DE0
 5160   LDX #&FF             :\ Prepare to return X=&FF - Not done
 5170   .L2DE2
 5180   INC &A4              :\ Increment sector number
 5190   TXA:PHA
 5200   LDX #&01:JSR L2A59   :\ Write sector in &A4 to sector in &FE86
 5210   PLA:TAX
 5220   .L2DED
 5230   RTS
 5240   :
 5250   \ Prepare to do a disk operation, NMIs claimed and set up
 5260   \ -------------------------------------------------------
 5270   .L2DEE
 5280   LDY #&06:LDA (&80),Y :\ Get drive+sector high
 5290   STA &A6              :\ Store drive number in b5-b7
 5300   AND #&1F:BNE L2E5A   :\ Keep sector b16-b20, jump if >&FFFF
 5310   BIT &A6:BVC L2E02    :\ Test drive b1 - drive 2,3,6,7
 5320   LDA #&65:STA &A0     :\ Result=&65 - Bad drive
 5330   BNE L2E5E            :\ Release and return
 5340   :
 5350   .L2E02
 5360   LDA &A6              :\ Get drive
 5370   AND #&20:BNE L2E0E   :\ If 1,5 skip
 5380   LDA #&21             :\ Something missing here?
 5390   LDA #&29:BNE L2E12   :\ Drive 0,4 control=&29 noRST+0+SDEN+SIDE0+0+DS0
 5400   .L2E0E
 5410   LDA #&22             :\ Something missing here?
 5420   LDA #&2A             :\ Drive 1,5 control=&2A noRST+0+SDEN+SIDE0+DS1+0
 5430   .L2E12
 5440   STA &0D5E            :\ Set drive selection setting
 5450   ROR L2EFA:SEC:ROL L2EFA :\ Set bit0 of L2EFA - seems to be unused
 5460   JSR L2E49            :\ Get sector/track/side and check for overflow
 5470   LDA &0D5E:STA &FE80  :\ Select drive and side
 5480   ROR A:BCC L2E37      :\ bit0=0, drive 1, skip past
 5490   :
 5500   \ Drive 0/4
 5510   LDY #&0B:LDA (&80),Y:STA &A3 :\ Get setting from length byte 0
 5520   LDY #&0A:LDA (&80),Y:ROL A   :\ Get flags byte, normally &00
 5530   BCC L2E48                    :\ If XY+10.bit7=0, exit
 5540   BCS L2E45                    :\ If XY+10.bit7=1, call something and exit
 5550   :
 5560   \ Drive 1/5
 5570   .L2E37
 5580   LDY #&0C:LDA (&80),Y:STA &A3 :\ Data setting from length byte 1
 5590   LDY #&0A:LDA (&80),Y         :\ Get flags byte, normally &00
 5600   ROL A:ROL A                  :\ Get bit 6
 5610   BCC L2E48                    :\ If XY+10.bit6=0, exit
 5620   :
 5630   \ If drive bit set in XY?10, set &A3 from length?drive,
 5640   \ then ignore &A3 and restore to track zero, wait for completion.
 5650   .L2E45
 5660   JSR L2C91                    :\ Restore to trck zero, wait for completion
 5670   .L2E48
 5680   RTS
 5690   :
 5700   \ So, XY+10 used as a bitmap of extra actions
 5710   \ %1xxxxxxx - drive 0 do a restore before action
 5720   \ %x1xxxxxx - drive 1 do a restore before action
 5730   :
 5740   .L2E49
 5750   LDY #&07:LDA (&80),Y :\ Get sector b8-b15
 5760   CMP #&06:BCC L2E7A   :\ <&600, ok
 5770   BNE L2E5A            :\ >&600, fail
 5780   INY:LDA (&80),Y      :\ Get sector b0-b7
 5790   CMP #&40:BCC L2E60   :\ <&640, ok
 5800   .L2E5A
 5810   LDA #&61:STA &A0     :\ Result=&61 - Sector out of range
 5820   .L2E5E
 5830   BNE L2EA2            :\ Release and return
 5840   :
 5850   \ Sector<&640 - valid sector for a floppy disk
 5860   .L2E60
 5870   LDA &A1
 5880   AND #&10:BEQ L2E7A
 5890   LDY #&09:LDA (&80),Y :\ Get sector count
 5900   DEY:CLC:ADC (&80),Y  :\ Add to start sector
 5910   BCS L2E74            :\ sec+num>&xxFF, fail
 5920   CMP #&41:BCC L2E7A   :\ sec+num<&641, ok
 5930   .L2E74
 5940   LDA #&63:STA &A0     :\ Result=&63 - Volume error
 5950   BNE L2EA2            :\ Release and return
 5960   \
 5970   \ Ah ha, &61 Sector error is start sector>end of disk
 5980   \ &63 Volume error is start+count>end of disk
 5990   :
 6000   \ Sector<&600 - valid for a floppy disk
 6010   .L2E7A
 6020   LDY #&07:LDA (&80),Y :\ Get sector b8-b15
 6030   TAX
 6040   INY:LDA (&80),Y      :\ Get sector b0-b7
 6050   LDY #&FF:JSR L2E96   :\ Y=sector DIV 10, A=sector MOD 10
 6060   STA &A4:STY &A5      :\ Set disk sector and track
 6070   TYA:SEC:SBC #&50     :\ Check for side 1
 6080   BMI L2EA1            :\ Track<80, exit
 6090   STA &A5              :\ Update with track-80
 6100   JMP L2C74            :\ Jump to select SIDE=1
 6110   :
 6120   DIV/MOD 10
 6130   \ ----------
 6140   .L2E96
 6150   SEC:SBC #&0A:INY:BCS L2E96
 6160   DEX:BPL L2E96:ADC #&0A      :\ Y=XA DIV 10, A=XA MOD 10
 6170   .L2EA1
 6180   RTS
 6190   :
 6200   \ Operation complete, release and set result
 6210   \ ------------------------------------------
 6220   .L2EA2
 6230   LDX L2EF4:TXS        :\ Restore stack
 6240   LDA L2EF1            :\
 6250   AND #&20:BEQ L2ED7   :\
 6260   LDA &0D5E            :\ Get drive control
 6270   ROR A                :\ Move DS0 into Carry
 6280   LDA &A3              :\ Get a value
 6290   BCC L2EC3            :\ DS0=0, skip to deal with drive 1
 6300   :
 6310   \ Store drive 0 byte in length.0 and clear bit7 in flag
 6320   LDY #&0B:STA (&80),Y :\ Store value in (ctrl),11
 6330   LDY #&0A:LDA (&80),Y :\ Get (ctrl),10
 6340   AND #&7F:STA (&80),Y :\ Remove bit7 and update
 6350   BCS L2ECF            :\ Skip past to get result
 6360   :
 6370   \ Store drive 1 byte in length.1 and clear bit6 in flag
 6380   .L2EC3
 6390   LDY #&0C:STA (&80),Y :\ Store value in (ctrl),12
 6400   LDY #&0A:LDA (&80),Y :\ Get (ctrl),10
 6410   AND #&BF:STA (&80),Y :\ Remove bit6 and update
 6420   :
 6430   .L2ECF
 6440   LDA &A0:STA L2EF3    :\ Store returned result
 6450   JSR L2B1C            :\ Release NMIs
 6460   :
 6470   .L2ED7
 6480   JSR L2B43             :\ Release Tube
 6490   LDY #&00
 6500   LDA L2EF3:STA (&80),Y :\ Store result in control block
 6510   LDX &80:DEX:DEX       :\ Get original X
 6520   LDA L2EF3:BEQ L2EEC   :\ Get result, skip if OK
 6530   ORA #&40              :\ Not OK, ORA with &40 to indicate FDD
 6540   .L2EEC
 6550   LDY &81               :\ Get original Y
 6560   AND #&7F:RTS          :\ Drop bit7 and return
 6570   \ Return value irrelevent as OSWORD handler restores original A
 6580   :
 6590   .L2EF1:EQUB &00       :\ Action, &10=Write, &11=Read
 6600   .L2EF2:EQUB &00       :\ Previous NMI owner
 6610   .L2EF3:EQUB &00       :\ Result - initially set to &00
 6620   .L2EF4:EQUB &00       :\ Saved stack pointer
 6630   .L2EF5:EQUB &00       :\ Disk speed &00 or &03
 6640   .L2EF6:EQUB &00       :\ Disk speed &00 or &02
 6650   BRK                   :\ 2EF7 00          .
 6660   BRK                   :\ 2EF8 00          .
 6670   BRK                   :\ 2EF9 00          .
 6680   .L2EFA:EQUB &00       :\ &00/&01 - never seems to be used
 6690   .L2EFB:EQUB &00       :\ &81=Tube being used, &80=Tube not being used
 6700   .L2EFC:EQUD &00000000 :\ Tube transfer address
 6710   :
 6720   \ WORDV entry
 6730   \ ===========
 6740   .exec%
 6750   .L2F00
 6760   JMP L2F05            :\ Jump to handler
 6770   .L2F03
 6780   EQUW 0               :\ oldUSERV store
 6790   .L2F05
 6800   CMP #&FE:BEQ L2F0C   :\ If OSWORD &FE, skip past
 6810   JMP (L2F03)          :\ Continue via oldUSERV
 6820   .L2F0C
 6830   JMP L2A00            :\ Jump to OSWORD &FE code
 6840   :
 6850   \ Left-over data
 6860   EQUS STRING$(&2F7A-P%,CHR$0)
 6870   EQUS " SEEK  "       :\ 2F7A 20 53 45 45  SEE
 6880   EQUB &01             :\ 2F7E 4B 20 20 01 K  .
 6890   EQUB &14             :\ 2F82 14          .
 6900   EQUB &00             :\ 2F83 00          .
 6910   EQUS STRING$(&2FC0-P%,CHR$0)
 6920   EQUS " SOFT  "       :\ 2FC0 20 53 4F 46  SOF
 6930   EQUB &01             :\ 2FC4 54 20 20 01 T  .
 6940   EQUB &00             :\ 2FC8 00          .
 6950   EQUB &00             :\ 2FC9 00          .
 6960   EQUS " TUBE  "       :\ 2FCA 20 54 55 42  TUB
 6970   EQUB &01             :\ 2FCE 45 20 20 01 E  .
 6980   EQUB &06             :\ 2FD2 06          .
 6990   EQUB &04             :\ 2FD3 04          .
 7000   EQUS STRING$(&3000-P%,CHR$0)
 7010 ]NEXT
 7020 A$=fname$+" "+STR$~mcode%+" "+STR$~O%+" "+STR$~(exec%OR&FFFF0000)+" "+STR$~load%
 7030 PRINT"Saving ";A$:OSCLI "SAVE "+A$:PRINT