10 REM >HADFS8 v5.69
   20 REM Disk Initialisation - *INSTALL and *FORMAT
   30 REM ==========================================
   40 REM v5.26 New install routine
   50 REM v5.27 Fixed install data flag, DiskID
   60 REM v5.53 Updating for 24-bit disk map, *INSTALL xxxxM
   70 REM       Format code needs re-examining, non-optimal on Master
   80 REM       Does DFS need to be selected for OSWORD &7F to work correctly?
   90 REM v5.66 Uses offset directory buffer
  100 REM v5.69 System boot runs on Electron
  110 :
  120 PRINT "Assembling S.HADFS8"
  130 O%=P%-Block%+mcode%
  140 [OPT0
  150 :
  160 \ ------------------------
  170 \ Check if command enabled
  180 \ ------------------------
  190 .CheckEnable
  200 BIT ENABLE:BVC NotEnabled:RTS
  210 .NotEnabled
  220 TYA:PHA:TXA:PHA
  230 JSR PrText:EQUS "Go? (Y/N) ":BRK
  240 LDA #21:LDX #0:JSR OSBYTE
  250 PLA:TAX:PLA:TAY
  260 JSR OSRDCH:BCS NotEnab2
  270 AND #&DF:CMP #ASC"Y":BNE NotEnab2
  280 JSR OSWRCH:JMP OSNEWL
  290 .NotEnab2
  300 JSR errors:EQUB 189:EQUS "Not enabled":BRK
  310 :
  320 :
  330 \ ================
  340 \ *Install routine
  350 \ ================
  360 .InstHelp
  370 LDX #CommInstall-CommTable          :\ Point to "INSTALL" text
  380 LDY #HelpInstall-HelpText           :\ Point to *Install help text
  390 JSR HelpLp2                         :\ Print a single *Help entry
  400 JSR PrText
  410 EQUS "<size> can be:":EQUB 13
  420 EQUS "L...     : Large Disk even if <16M":EQUB 13
  430 \EQUS "D...     - data disk":\EQUB 13
  440 EQUS "<dec>    : tracks":EQUB 13
  450 EQUS "<dec>K|M : bytes":EQUB 13
  460 EQUS "&<hex>   : sectors":EQUB 13
  470 BRK
  480 :]:IF _NoInsHlp%:z%=P%-InstHelp:P%=P%-z%:O%=O%-z%
  490 RTS
  500 :
  510 \ ----------------
  520 \ *Install command
  530 \ ----------------
  540 .Install
  550 LDA CSD+d:STA drive                 :\ Assume using current drive
  560 JSR GetChar:BEQ InstDrive           :\ No parameters, do default action
  570 CMP #ASC"?":BNE P%+5:JMP InstHelp   :\ Print out *Install help text
  580 INY:LDA (&F2),Y:DEY                 :\ Get char after current char
  590 CMP #ASC"!":BCS InstDrive           :\ If not separator, use current drv
  600 JSR GetDrive
  610 .InstDrive                          :\ DRIVE now holds drive to use
  620 JSR ReadFSM                         :\ EQ=HADFS disk, NE=blank
  630 CLC:PHP                             :\ CC=new install
  640 JSR SkipSpc                         :\ Look for next parameter
  650 INY:CMP #ASC"$":BEQ InstRoot        :\ '$' -> create new disk
  660 DEY:PLP:BEQ P%+5:JMP NotHADFSDisk   :\ Update must be of HADFS disk
  670 SEC:PHP                             :\ CS=update existing disk
  680 :
  690 .InstRoot
  700 \ On entry here, pushed flags
  710 \  NE=not HADFS disk (ie blank)  EQ=HADFS disk
  720 \  CC=do new install ($)         CS=update disk
  730 :
  740 JSR SkipSpc:BEQ InstNoTitle         :\ No new disk title
  750 LDX #0
  760 .InstTitle
  770 STA FSM,X:INY:LDA (&F2),Y           :\ Copy new disk title in
  780 CMP #ASC"!":BCC InstPad             :\ End at space or <cr>
  790 INX:CPX #16:BNE InstTitle           :\ Loop for 16 characters
  800 JMP errBadFilename                  :\ This disallows titles exactly 16 characters long
  810 .InstPad
  820 LDA #ASC" "
  830 .InstSpc
  840 INX:STA FSM,X                       :\ Pad title with spaces
  850 CPX #16:BNE InstSpc                 :\ Title length is 16 chars
  860 .InstJGH
  870 LDA JGHName-16,X:STA FSM,X:INX      :\ Put validity string in
  880 CPX #24:BNE InstJGH
  890 :
  900 .InstNoTitle
  910 LDA #0                              :\ Prepare cleared flags
  920 PLP:BCC P%+5:JMP InstUpdate         :\ Jump ahead to update existing disk
  930 PHP:BNE InstBlank                   :\ New install on blank disk
  940 LDA FSM+31:ASL A:BPL InstOverwrite  :\ New install on existing unlocked disk
  950 JMP errLocked                       :\ Can't overwrite locked disk
  960 .InstOverwrite
  970 LDA #&C1                            :\ Keep BigDisk+Locked+NoDFS flags
  980 .InstBlank                          :\ **** FAILING SOMEWHERE ****
  990 AND FSM+31:STA FSM+31               :\ Clear disk flags
 1000 :
 1010 \ Overwriting disk - Creating new disk
 1020 \ ------------------------------------
 1030 JSR SkipSpc:AND #&DF                :\ Get next character
 1040 CMP #ASC"@":BCC P%+3:INY
 1050 PLP:PHA:PHP                         :\ Save any prefix character
 1060 :
 1070 \ From here on,
 1080 \  Pushed A='S','L','D', <cr>, etc
 1090 \ Pushed flags
 1100 \  NE=not HADFS disk (ie blank)  EQ=HADFS disk
 1110 \  CC=do new install ($)
 1120 :
 1130 JSR SkipSpc:BNE InstSize            :\ Disk size given, parse it
 1140 PLP:BEQ InstEnable                  :\ Use existing disk size
 1150 :                                   :\ If no size given, allow GetNumber
 1160 :                                   :\ to generate error later on
 1170 .InstSize
 1180 PLP:INY:CMP #ASC"&":BEQ InstNum     :\ Drop NE/EQ flag, check for &sectors
 1190 DEY:CLC                             :\ CC=decimal, CS=hex
 1200 .InstNum
 1210 PHP:JSR GetNumber                   :\ Read size parameter
 1220 PLP:BCS InstSectors:AND #&DF        :\ &xxxx is actual sector size
 1230 :
 1240 LDY #2:CMP #ASC"K":BEQ InstNumLp    :\ Convert xxxxK to sectors
 1250 CMP #ASC"M":BNE InstTrk:LDY #12     :\ xxxx is number of tracks
 1260 .InstNumLp
 1270 JSR TimesTwo:DEY:BNE InstNumLp      :\ Convert K or M to sectors
 1280 BEQ InstSectors                     :\ TimesTwo returns flags preserved
 1290 :
 1300 .InstTrk
 1310 JSR Times10                         :\ Multiply tracks by 10 to get sectors
 1320 :
 1330 .InstSectors
 1340 CLC:LDA numstore+3                  :\ Flag ENABLE not yet checked
 1350 BEQ P%+5:JMP errBadNumber           :\ If 4G+, error, disk too big
 1360 :
 1370 .InstFormat
 1380 \ When *FORM enters here, ENABLE already checked
 1390   \------------------------------------------------
 1400   \ On entry here,
 1410   \  TITLE, JGHNAME set, numstore holds SIZE
 1420   \  pushed A=disk type character
 1430   \         CC Check ENABLE   CS Don't check ENABLE
 1440   \------------------------------------------------
 1450   PLA:PHA:EOR #ASC"L":BEQ InstBig     :\ Force to BigDisk if L<size>
 1460   LDA #&7F:AND FSM+31:\STA FSM+31     :\ Remove BigDisk flag
 1470   LDX numstore+2:BEQ P%+4             :\ If <16M, leave set to SmallDisk
 1480   .InstBig
 1490   ORA #&80:STA FSM+31:LDX #2          :\ Set DiskSize flag
 1500   .InstLp1
 1510   LDA numstore,X:STA FSM+&1C,X        :\ Put sector count into SIZE
 1520   DEX:BPL InstLp1
 1530   :
 1540   .InstEnable
 1550   BCS P%+5:JSR CheckEnable            :\ Is command enabled?
 1560   LDA #0:STA fptr+0
 1570   LDA #FSM DIV 256:STA fptr+1         :\ Point to disk creation date
 1580   SEC:JSR SetCrDateFSM                :\ Set disk creation date
 1590   :
 1600   LDA &296:LDX #30                    :\ Seed disk ID with part of TIME
 1610   .MakeID
 1620   PHA:TYA:EOR FSM+0,X                 :\ Hash the disk info into an ID
 1630   TAY:PLA:ADC FSM+1,X
 1640   DEX:DEX:BPL MakeID:STA FSM+&18      :\ Set DiskID
 1650   EOR &295:STA FSM+&19                :\ Merge in another part of TIME
 1660   :
 1670   LDX #32:LDA #0
 1680   .InstEmptyFSM                       :\ Create an empty FSM
 1690   STA FSM,X:INX:BNE InstEmptyFSM      :\ Blank all entries
 1700   LDA FSM+31:ASL A:BCS InstEmptyBig   :\ Empty BigDisk
 1710   DEX:LDA #1:STA FSM+30               :\ Make SmallDisk a Data disk
 1720   .InstEmptyBig
 1730   INX:LDA #2:STA FSM+32               :\ First FSM entry start is &0002
 1740   LDA #68:STA FSM+34,X                :\ First FSM entry length is &0044
 1750   TXA:PHA:BCC P%+3:INX                :\ Save pointer to first entry
 1760   LDA #74:STA FSM+36,X                :\ Second entry &004A+xxxx
 1770   BCC P%+3:INX:SEC
 1780   LDA FSM+&1C:SBC #74:STA FSM+38,X
 1790   LDA FSM+&1D:SBC #00:STA FSM+39,X
 1800   LDA FSM+&1E:SBC #00:STA FSM+40,X    :\ Length is to end of disk
 1810   PLA:TAX                             :\ Get pointer to first entry
 1820   BNE P%+5:STA FSM+40                 :\ Clear SmallDisk end of FSM byte
 1830   PLA:CMP #ASC"S":BNE InstNew
 1840   LDA #4:STA FSM+34,X:LDA #0          :\ System disk, reduce space for ROM image
 1850   .InstNew
 1860   CLC                                 :\ CC=overwrite, NE=Data, EQ=Syst
 1870   :
 1880   \---------------------------
 1890   \ InstUpdate - Update a disk
 1900   \---------------------------
 1910   \ On entry here,
 1920   \  TITLE, JGHNAME, DATE, DSKID, SIZE, FLAGS set
 1930   \         P -> CS=update,   CC=overwrite
 1940   \              NE/EQ=xxx    NE=Data, EQ=Syst
 1950   \----------------------------------------------
 1960   .InstUpdate
 1970   PHP
 1980   LDA #0:STA VFLG:JSR SaveFSM         :\ Clear names, save the new or updated FSM
 1990   :
 2000   \ We always update so old versions can understand, even if we lose some space
 2010   \  Update SmallData -> dual boot, 16-bit FSM, update any $.HADFSROM file
 2020   \  Update SmallSyst -> dual boot, 16-bit FSM, update embedded ROM
 2030   \  Update BigDisk   -> dual boot, 24-bit FSM, update any $.HADFSROM file
 2040   \
 2050   \ We always create as disk with dual boot
 2060   \  Create SmallData -> dual boot, 16-bit FSM
 2070   \  Create SmallSyst -> dual boot, 16-bit FSM, save $.HADFSROM file
 2080   \  Create BigDisk   -> dual boot, 24-bit FSM, save $.HADFSROM file
 2090   :
 2100   LDA FSM+31:AND #&41:BNE InstNoDFS   :\ Don't overwrite sectors 0/1
 2110   .InstDFS
 2120   JSR ClearDIR:JSR dirInit            :\ Use DIR buffer, fptr=>DIR, Y=0
 2130   STY sect+0:STY sect+1:STY sect+2    :\ Set SECT to &000000
 2140   LDA #BootCode AND 255:STA addr+0
 2150   LDA #BootCode DIV 256:STA addr+1
 2160   JSR InstCopyMem                     :\ Save data to disk
 2170   :
 2180   .InstNoDFS
 2190   LDA #6:STA sect+0
 2200   LDA #0:STA sect+1:STA sect+2        :\ Pre-assume HADFSROM is at &0006 for OldSyst
 2210   PLP:PHP:BCC InstROMUpd              :\ Create ROM at &0006 for new disk
 2220   LDA FSM+31:BMI InstROMFind          :\ BigDisk, look for $.HADFSROM
 2230   LDA FSM+30:LSR A:BCC InstROMUpd2    :\ SmallDisk, SystDisk, embedded ROM at &0006
 2240   :
 2250   \ BigDisk or SmallData, look for $.HADFSROM
 2260   .InstROMFind
 2270   LDA #ROMName AND 255:STA &F2
 2280   LDA #ROMName DIV 256:STA &F3
 2290   LDY #0:JSR LookFromRoot2            :\ Look for $.HADFSROM on current drive
 2300   CMP #1:BNE InstNoROM                :\ $.HADFSROM doesn't exist as a file
 2310   CLC:JSR GetLength
 2320   JSR GetSectAddr                     :\ sect=file start
 2330   LDA len+1:CMP #&40:BNE InstNoROM    :\ Length not &xx40xx
 2340   LDA len+2:ORA len+0:\BNE InstNoROM  :\ Length not &00xx00
 2350   :
 2360   \ sect=start of $.HADFSROM file or start of embedded ROM
 2370   .InstROMUpd
 2380   BNE InstNoROM                       :\ Create Data disk
 2390   .InstROMUpd2
 2400   JSR ClearDIR                        :\ Use DIR buffer, A=0
 2410   STA addr+0:LDA #&80                 :\ addr=&8000, ROM start
 2420   .InstROMlp
 2430   STA addr+1:PHA                      :\ Save source address
 2440   JSR dirInit:JSR InstCopyMem         :\ Copy two pages from addr to fptr, and save it
 2450   PLA:CLC:ADC #2                      :\ Update addr
 2460   CMP #&C0:BCC InstROMlp              :\ Loop to end of ROM
 2470   :
 2480   \ Any required $.HADFSROM or embedded ROM updated
 2490   \ Now, install blank root directory if needed
 2500   \  pushed P -> CS=update,   CC=overwrite
 2510   \              NE/EQ=xxx    NE=Data, EQ=Syst
 2520   \------------------------------------------------
 2530   .InstNoROM
 2540   PLP:BCS InstDone:PHP                :\ Updating, so no new root needed
 2550   JSR ClearDIR:JSR dirInit:TYA        :\ Use DIR buffer, fptr=>DIR, Y=0
 2560   .InstRootLp1
 2570   CPY #9:BNE P%+4:LDA #32             :\ First 10 bytes are spaces
 2580   STA (fptr),Y:DEY:BNE InstRootLp1    :\ Blank out directory
 2590   LDA #ASC"$":STA (fptr),Y            :\ Set directory name
 2600   LDA FSM+24:LDY #16:STA (fptr),Y
 2610   LDA FSM+25:INY:STA (fptr),Y         :\ Set DiskID
 2620   LDA FSM+31:AND #&80                 :\ Get BigDisk flag
 2630   LDY #12:STA (fptr),Y                :\ If BigDisk, also BigDir
 2640   LDY #10:TAX:BPL P%+4:LDY #&1C       :\ Y=>Parent
 2650   LDA #71:STA (fptr),Y                :\ Set Parent=$
 2660   PLP:BNE InstRootSave                :\ Data disk, no $.HADFSROM file
 2670   LDY #12:LDA #1:STA (fptr),Y         :\ Entries=1
 2680   JSR dirNext                         :\ fptr=>first directory entry, Y=0
 2690   .InstRootLp2
 2700   LDA ROMName,Y:STA (fptr),Y          :\ Copy 'HADFSROM' filename into dir
 2710   INX:INY:CPY #10:BNE InstRootLp2
 2720   LDA #&40:LDY #&13:STA (fptr),Y      :\ Length=&004000
 2730   LDA #&06:LDY #&16:STA (fptr),Y      :\ Sector=&000006
 2740   .InstRootSave
 2750   JSR SectRoot:JMP PutDirNoHdr        :\ Save the root directory and exit
 2760   .InstDone
 2770   RTS                                 :\ All finished
 2780   :
 2790   \ Copy data from (addr) to DIR buffer
 2800   \ -----------------------------------
 2810   .InstCopyMem
 2820   LDX #2:LDY #0:STX num               :\ Copy two pages, two sectors to save
 2830   .InstCopyMemLp
 2840   LDA (addr),Y:STA (fptr),Y           :\ Copy code to DIR buffer
 2850   INY:BNE InstCopyMemLp
 2860   INC addr+1:INC fptr+1               :\ Point to next page
 2870   DEX:BNE InstCopyMemLp
 2880   DEX:STX action                      :\ action=&FF - Write
 2890   JMP DiskAccDIR                      :\ Write from DIR, sect updated
 2900   :
 2910   \------------------------------------------
 2920   \ Boot sector code - 512 bytes of code with
 2930   \ DFS catalogue and !Boot boot code
 2940   \------------------------------------------
 2950   .BootCode:]:BootOff=BootCode-&900
 2960   :]:BootOsw7F=&08C0:BootAddr=BootOsw7F+1
 2970   :]:BootZP=&A8:BootROM=&AA:BootNum=&AC:BootOS=&AD
 2980   EQUS "HADFS"+CHR$0+" D"
 2990   .BootCmd
 3000   EQUS "!Boot  "+CHR$164
 3010   EQUD 13:EQUD 0                :\ Disk Parameter Table
 3020   EQUS "$       ":EQUW &20A0    :\ Fake entry for '$'
 3030   .ROMName
 3040   EQUS "HADFSROM  "
 3050   EQUW &0000:EQUW &0047         :\ Sector of '$'
 3060   :
 3070   .BootGo%
 3080   LDY #0:JSR Osbyte90_6-BootOff :\ Get HADFS status
 3090   TXA:BPL BootUp                :\ HADFS present, boot it
 3100   LDX #1:AND #&40:BNE BootLdROM :\ No HADFS, load it
 3110   LDA #143:LDY #&E:JSR OSBYTE   :\ Redeclare shared workspace
 3120   LDX #2:JSR OSBYTE:STY &244    :\ Redeclare private workspace
 3130   .BootUp
 3140   LDY #2                        :\ *FX90,6,2 - Boot from HADFS
 3150   :
 3160   .Osbyte90_6                   :\ Generic Osbyte 90,6,y routine
 3170   LDX #6
 3180   .Osbyte90                     :\ Generic Osbyte 90,x,y routine
 3190   LDA #90:JMP OSBYTE
 3200   :
 3210   .BootLdROM:\ X=1 when here
 3220   LDA #0:JSR OSBYTE:TXA:BNE BootLd1
 3230   LDA #&05:STA RomSelOne+3-BootOff:\ Change RomSelect for Electron
 3240   .BootLd1
 3250   LDX #15                       :\ Look for a bank of RAM
 3260   .BootLp
 3270   JSR RomSelect-BootOff         :\ Select ROM number X
 3280   LDA &8008:INC &8008:CMP &8008 :\ Test if RAM
 3290   BNE BootRAMFound              :\ RAM found
 3300   DEX:BPL BootLp                :\ Loop for all 16 banks
 3310   INX:JMP BootPrText-BootOff    :\ No RAM found
 3320   :
 3330   .BootRAMFound
 3340   LDA #0:LDX #&47:LDY #3        :\ Read 3 sectors from &0047
 3350   JSR BootRd-BootOff:LDX #6     :\ Load '$' directory, BootZP=&3000, default sector=6
 3360   .BootNxtName
 3370   LDY #0:CLC
 3380   LDA BootZP+0:ADC #24:STA BootZP+0 :\ Step through SmallDir entries
 3390   LDA BootZP+1:ADC #00:STA BootZP+1 :\ Tweek to allow BigDir entries
 3400   CMP #&33:LDA #0:BCS BootEndOfDir  :\ End of directory, try embedded ROM at &AAXX=&0006
 3410   .BootChkChr
 3420   LDA (BootZP),Y:AND #&5F       :\ Get filename character
 3430   CMP ROMName-BootOff,Y
 3440   BNE BootNxtName               :\ Not 'HADFSROM', step to next
 3450   INY:CPY #8:BNE BootChkChr     :\ Check 8 characters
 3460   :
 3470   LDY #22:LDA (BootZP),Y:TAX    :\ X=sector low byte
 3480   INY:LDA (BootZP),Y            :\ A=sector high byte
 3490   .BootEndOfDir
 3500   LDY #&40:JSR BootRd-BootOff   :\ Read &40 sectors from &AAXX, returns Y=0
 3510   :
 3520   LDX #&40:STY BootROM+0        :\ &40 pages to copy
 3530   LDA #&80:STA BootROM+1        :\ BootROM=>&8000
 3540   .BootCopyLp
 3550   LDA (BootZP),Y:STA (BootROM),Y:\ Copy byte to ROM
 3560   INY:BNE BootCopyLp            :\ Loop for 256 bytes
 3570   INC BootZP+1:INC BootROM+1    :\ Update pointers
 3580   DEX:BNE BootCopyLp            :\ Loop for &40 pages
 3590   \ NB, doesn't actually check if loaded data is a ROM
 3600   :
 3610   .BootROMReset
 3620   LDA #3:STA &190+200           :\ *FX200,3
 3630   TXA:INX:JSR OSBYTE            :\ Read host
 3640   CPX #5:BCS BootReset          :\ Compact - don't power reset
 3650   JSR ChkMOS350-BootOff
 3660   BEQ BootReset                 :\ MOS 3.50 - don't power cycle
 3670   .BootPower
 3680   LDA #151:LDX #78:LDY #127:JSR OSBYTE:\ Power reset
 3690   .BootReset
 3700   BIT &27A:BMI BootNoReset      :\ If Tube, stall
 3710   JMP (-4)                      :\ Otherwise, vector to reset code
 3720   .BootNoReset
 3730   LDX #BootBreak-BootText       :\ Point to 'Press BREAK' text
 3740   .BootPrText
 3750   LDA BootText-BootOff,X:BEQ P% :\ End of text, stall
 3760   JSR OSASCI:INX:BNE BootPrText
 3770   :
 3780   EQUS STRING$(&A00-(P%-BootOff),CHR$0)
 3790   EQUS "ISK "+CHR$0+CHR$8+CHR$&20+CHR$&02
 3800   EQUW &900:EQUW BootGo%-BootOff:EQUW &0200:EQUB &CC:EQUB 0
 3810   :
 3820   .ChkMOS350
 3830   LDX &EED5:CPX #ASC"M":BNE ChkMOS350a
 3840   LDX &EEDB:CPX #ASC"5"
 3850   .ChkMOS350a
 3860   RTS
 3870   :
 3880   .BootRd
 3890   STX BootZP+0                    :\ SectorLo
 3900   STA BootZP+1                    :\ SectorHi
 3910   STY BootNum                     :\ Number
 3920   LDX #&00:STX BootAddr+0         :\ Load to &xx00
 3930   LDA #&30:STA BootAddr+1         :\ Load to &3000
 3940   DEX:STX BootOsw7F+0             :\ Drive=-1 - Current drive
 3950   STX BootOsw7F+3:STX BootOsw7F+4 :\ Addr high word
 3960   LDA #&03:STA BootOsw7F+5        :\ Params=3
 3970   LDA #&53:STA BootOsw7F+6        :\ READ
 3980   :
 3990   .BootDiv10
 4000   INX:SEC
 4010   LDA BootZP+0:SBC #10:STA BootZP+0
 4020   LDA BootZP+1:SBC #00:STA BootZP+1
 4030   BCS BootDiv10:LDA BootZP:ADC #10    :\ X=Trk, A=Sec
 4040   STX BootOsw7F+7:STA BootOsw7F+8     :\ Trk, Sec
 4050   :
 4060   .BootRdNxt
 4070   LDA BootNum:TAY
 4080   CLC:ADC BootOsw7F+8:CMP #11         :\ Spans past end of track?
 4090   BCC BootNoSpan
 4100   LDA #10:SEC:SBC BootOsw7F+8:TAY     :\ Number to end of track
 4110   .BootNoSpan
 4120   TYA:ORA #&20:STA BootOsw7F+9        :\ Num
 4130   :
 4140   .BootRetry
 4150   LDX #9:.BootSvLp
 4160   LDA BootOsw7F,X:PHA:DEX:BPL BootSvLp
 4170   LDX #BootOsw7F AND 255:LDY #BootOsw7F DIV 256
 4180   LDA #&7F:JSR OSWORD
 4190   LDX #0:.BootRestLp
 4200   PLA:STA BootOsw7F,X:INX:CPX #10:BNE BootRestLp
 4210   AND #&1F:TAX:STA BootOsw7F+9        :\ Num
 4220   LDA BootOsw7F+10:BNE BootRetry
 4230   :
 4240   STA BootOsw7F+8:INC BootOsw7F+7       :\ Sec=0, Trk=Trk+1
 4250   TXA:CLC:ADC BootAddr+1:STA BootAddr+1 :\ Update address
 4260   LDA BootNum:SEC:SBC BootOsw7F+9       :\ Update length
 4270   STA BootNum:BNE BootRdNxt             :\ Read from next track
 4280   :
 4290   TAY:STY BootZP:LDX #&30:STX BootZP+1  :\ BootZP=&3000, Y=0
 4300   RTS
 4310   :
 4320   .RomSelect
 4330   LDA #12:JSR RomSelOne-BootOff:TXA:STA &FF30,X
 4340   .RomSelOne
 4350   STA &F4:STA &FE30:RTS
 4360   :
 4370   \.\BootWantSystem
 4380   \\LDX #BootSystem-BootText
 4390   \\JSR BootPrText-BootOff
 4400   \\CLI:\JSR &FFE0:\JSR &FFE7
 4410   \\LDX #(BootCmd-BootOff) AND 255
 4420   \\LDY #(BootCmd-BootOff) DIV 256:\JMP &FFF7
 4430   :
 4440   .BootText
 4450   EQUS "No SRAM":BRK:\ No sideways RAM
 4460   .BootBreak
 4470   EQUB 22:EQUB 7:EQUB 13:EQUS "Press BREAK":BRK:\ to reset
 4480   \\.BootSystem
 4490   \\EQUS "Not a system disk":\BRK
 4500   :
 4510   \\.BootRWrite
 4520   \\EQUS "RWRITE E.":\EQUB 13
 4530   EQUS "v"+ver$:BRK
 4540   :
 4550   :
 4560   \ ===============
 4570   \ *Format routine
 4580   \ ===============
 4590   .Form
 4600   CLC:JSR GetNumber:LDA numstore      :\ Get decimal number
 4610   CMP #10:BCS P%+5:JMP errBadNumber
 4620   PHA:JSR SkipSpc:BNE FormDsk3
 4630   .FormBadDrv
 4640   JMP errBadDrive
 4650   .FormDsk3
 4660   CMP #ASC"0":BCC FormBadDrv          :\ <'0' - Bad drive
 4670   CMP #ASC"4":BCS FormBadDrv          :\ >'3' - Bad drive
 4680   AND #3:CMP #2:BCC FormDsk4          :\ <'2' - Valid drive number
 4690   JSR ChkROM:BEQ FormBadDrv           :\ >'1' and HADFS, Bad drive
 4700   .FormDsk4
 4710   JSR GrabAbs:STA &F90:STA &F91       :\ &F90=current drive, &F91=start drive
 4720   JSR ClearFSM:LDA #0:STA &F92        :\ &F92=&00 for single-sided
 4730   STA &F94:PLA:STA &F95               :\ &F94=current track, &F95=tracks per side
 4740   STA &F96:CMP #103:BCC FormDsk5      :\ &F96=total tracks, 102 tracks is biggest DFS size
 4750   LSR &F95:DEC &F92                   :\ Double sided, half number of tracks, &F92=&FF
 4760   .FormDsk5
 4770   LDA &F90:CMP #2:BCC FormDsk6
 4780   LDA #0:STA &F92                     :\ Drive 2/3, set to single-sided
 4790   .FormDsk6
 4800   JSR PrText:EQUS "Format drive ":BRK
 4810   LDA &F90:JSR PrNyb:JSR OSNEWL       :\ Print current drive number
 4820   JSR ChkROM:BEQ FormDsk1             :\ HADFS, check ENABLE flag
 4830   JSR NotEnabled:JMP FormDsk2         :\ Not HADFS, ask to be enabled
 4840   .FormDsk1
 4850   JSR CheckEnable
 4860   :
 4870   .FormDsk2
 4880   LDA #7:STA &F93                     :\ &F93=Set initial skew
 4890   .FormDskLoop
 4900   LDA &F90:JSR FormTrack              :\ Format a single track
 4910   BIT &FF:BPL P%+5:JMP FormExit       :\ Quit if Escape pressed
 4920   INC &F94:LDA &F94:CMP &F95          :\ Increment current track
 4930   BNE FormDskLoop                     :\ Loop back until all done
 4940   BIT &F92:BPL FormDsk7a              :\ Single-sided -> create blank disk
 4950   LDA &F90:CMP #2:BCS FormDsk7a       :\ Drive 2/3 -> create blank disk
 4960   ORA #2:STA &F90                     :\ Set to drive 2/3 for side 1
 4970   LDA #0:STA &F94:BEQ FormDskLoop     :\ Reset to track zero, do second side
 4980   :
 4990   .FormDsk7a
 5000   JSR OSNEWL:LDA &F91:STA drive       :\ Set drive
 5010   LDA &F96:STA numstore:LDA #0:LDX #3 :\ numstore?0=tracks
 5020   .FormDsk7b
 5030   STA numstore,X:DEX:BNE FormDsk7b    :\ numstore=tracks
 5040   JSR Times10:LDA #0:TAX              :\ numstore=tracks*10
 5050   .FormZero
 5060   STA FSM,X:INX:BNE FormZero          :\ Fill sector with zeros
 5070   JSR ChkROM:BNE FormDFS:LDX #23      :\ HADFS not selected, install DFS
 5080   .FormJGH                            :\ Put blank HADFS data in
 5090   LDA JGHName-16,X:STA FSM,X:DEX:BPL FormJGH
 5100   LDA #1:STA FSM+30                   :\ Flag as OldData disk
 5110   PHA:SEC                             :\ Pushed A=NotSyst, CS=ENABLE already checked
 5120   JMP InstFormat                      :\ Create disk, CS=don't check ENABLE
 5130   :
 5140   .FormDFS
 5150   STA sect+0:STA sect+1:STA sect+2    :\ Sector &0000
 5160   LDA drive:PHA:AND #1:STA drive      :\ Set drive to 0/1
 5170   PLA:AND #2:BEQ FormDFSb             :\ Jump to save to drive 0/1
 5180   LDA #&20:STA sect+0
 5190   LDA #&03:STA sect+1                 :\ Drive 2/3 - sect=&320 for side 1
 5200   .FormDFSb
 5210   JSR SavePageF                       :\ Save empty sector, sect updated to &0001
 5220   LDA numstore+0:STA FSM+7
 5230   LDA numstore+1:STA FSM+6            :\ Set disk size
 5240   JMP SavePageF                       :\ Save sector &0001
 5250   :
 5260   .ChkROM
 5270   LDX XFILEV+2:CPX &F4:RTS            :\ Is HADFS current filing system?
 5280   :
 5290   \ FormTrack - format a track
 5300   \ --------------------------
 5310   \ On entry, A=DFS drive number
 5320   .FormTrack
 5330   STA &F80:PHA:LDA #13:JSR OSWRCH
 5340   JSR PrText:EQUS "Formatting ":BRK
 5350   PLA:JSR PrNyb:LDA #ASC":":JSR OSWRCH
 5360   LDA &F94:JSR PrHex
 5370   .FormTrkLp
 5380   LDX #10:BIT &FF:BPL FormSectLp1
 5390   .FormExit
 5400   RTS
 5410   .FormSectLp1
 5420   LDA FormTable,X:STA &F81,X
 5430   DEX:BPL FormSectLp1
 5440   LDA &F94:STA &F87:\ track
 5450   LDX #0:\ Set up sector table
 5460   .FormSectLp2
 5470   LDA &F94:STA &F00,X
 5480   LDA #0:STA &F01,X
 5490   LDA &F93:STA &F02,X:INC &F93
 5500   CMP #9:BCC FormSect2
 5510   LDA #0:STA &F93
 5520   .FormSect2
 5530   LDA #1:STA &F03,X
 5540   INX:INX:INX:INX:CPX #40
 5550   BNE FormSectLp2
 5560   LDA &F93:SBC #3:BPL FormSect3
 5570   ADC #10:.FormSect3:STA &F93
 5580   :
 5590   \ Wrap this in SelectDFS ?
 5600   LDX #&80:LDY #&F:LDA #&7F
 5610   JSR OSWORD
 5620   :
 5630   LDA &F8C:BEQ FormExit
 5640   CMP #&12:BCC FormTrkLp
 5650   BNE P%+5:LDA #&12:JMP DiskErrors    :\ Read only
 5660   CMP #&14:BEQ FormTrkLp
 5670   LDA #ASC"?":JSR OSWRCH:JMP OSNEWL
 5680   .FormTable
 5690   EQUD &FFFF0F00:\ =sectab
 5700   EQUB &5:EQUB &63:\ =format
 5710   EQUB 0:\ track
 5720   EQUB &10:\ gap3
 5730   EQUB &2A:\ sector num + size
 5740   EQUB &00:\ gap5
 5750   EQUB &10:\ gap1
 5760   :]:IF _NoFormat%:z%=P%-Form:P%=P%-z%:O%=O%-z%
 5770   :
 5780   :
 5790   \\\ Overlap dummy module headers with code:
 5800   \\EQUW NullKbd_Lnk            :\ x-2
 5810   \\.DummyHeader
 5820   \\:
 5830   \\.PutInInfo                  :\ Five bytes overlapped here
 5840   \\STA &F00,Y:\INY:\RTS
 5850   \\:
 5860   \\.DummyFinal
 5870   \\EQUW &0000                  :\ x+5  \\two spare bytes
 5880   \\EQUB JGHName-DummyHeader  :\ x+7
 5890   \\BRK                         :\ x+8
 5900   \\EQUS "NullKeyboard":\BRK:\EQUS "0.12 (01 Aug 1998)"
 5910   \\BRK
 5920   \\:
 5930   \\.NullKbd_Lnk
 5940   \\EQUW DummyFinal             :\ x-2
 5950   \\.NullKbd_0
 5960   \\.GetChn
 5970   \\LDY #0:\LDA (blk),Y
 5980   \\RTS:\BRK:\BRK
 5990   \\\.DummyCopy
 6000   \\\BRK:\EQUS "(C)JGH"           :\ x+0, \\DummyCopy-NullKbd_0 = 0
 6010   \\\.DummyFinal
 6020   \\EQUB JGHName-NullKbd_0:\BRK:\ x+7, x+8
 6030   \\EQUS "SoftRTC":\BRK:\EQUS "0.10 (23 Nov 1992)"
 6040   \\BRK
 6050   \\:
 6060   
 6070   \\ New module header layout
 6080   
 6090   .PutInInfo
 6100   STA &F00,Y:INY:RTS
 6110   .GetChn
 6120   LDY #0:LDA (blk),Y
 6130   .NULL
 6140   RTS
 6150   :
 6160   \EQUW Dummy2-2:\ For compatability with old *SMList command
 6170   .Dummy1
 6180   JSR Service:JMP Dummy2
 6190   EQUB 0:EQUB JGHName-Dummy1:EQUB 0
 6200   EQUS "NullKeyboard":EQUB 0
 6210   EQUS "0.12 (01 Aug 1998)":EQUB 0
 6220   :
 6230   \EQUW Dummy2-4:\ For compatability with old *SMList command
 6240   .Dummy2
 6250   JSR NULL:JMP NULL
 6260   EQUB 0:EQUB JGHName-Dummy2:EQUB 0
 6270   EQUS "SoftRTC":EQUB 0
 6280   EQUS "0.10 (23 Nov 1992)":EQUB 0
 6290   :
 6300   \\\
 6310   
 6320   .Trk_70
 6330   EQUS "(Untitled_Disk) "
 6340   .JGHName
 6350   EQUB 0:EQUS "(C)JGH":EQUB 0
 6360   
 6370   ]
 6380   PRINT CHR$11;STRING$(20,CHR$9);O%-mcode%;" bytes"
 6390   >"S.HADFS9"