10 REM > MakeRFS 1.00 14-Dec-2016 J.G.Harston
   20 :
   30 IF HIMEM-LOMEM<&4200:MODE 7
   40 PRINT"Build fast ROMFS ROM"
   50 DIM ctrl% 19, name% 255, mem% &3FFF:X%=ctrl%:Y%=X%DIV256
   60 INPUT LINE "ROM title:        "title$:IF title$="":title$="ROMFS"
   70 INPUT LINE "ROM copyright: (C)"copy$
   80 PROCcrc:PROCheader
   90 PRINT "Enter files to add, end with RETURN"
  100 REPEAT
  110   INPUT LINE "File to add:      "in$
  120   IF in$<>"":INPUT LINE "Filename to use:  "name$:IF name$="":name$=in$
  130   IF in$<>"":PROCadd
  140 UNTIL in$=""
  150 ?O%=ASC"+":O%=O%+1
  160 REPEAT:INPUT LINE "Save ROM as:      "out$:IF out$="":VDU11
  170 UNTIL out$<>"":A$="SAVE "+out$+" "+STR$~mem%+" "+STR$~O%+" 0 FFFBBC00"
  180 PRINT"Saving ";out$;:OSCLIA$:PRINT
  190 END
  200 :
  210 DEFPROCcrc
  220 DIM crc16% 40:crc=&70:addr=&72:num=&74
  230 FOR opt%=0 TO 2 STEP 2
  240   P%=crc16%
  250   [OPT opt%
  260   .bytelp:LDX #8:LDA (addr-8 AND &FF,X):EOR crc+0
  270   .rotlp:ASL crc+1:ROL A:BCC clear
  280   TAY:LDA crc+1:EOR #&21:STA crc+1:TYA:EOR #&10
  290   .clear:DEX:BNE rotlp:STA crc+0:INC addr+0:BNE next:INC addr+1
  300   .next:DEC num:BNE bytelp:RTS
  310 ]NEXT
  320 ENDPROC
  330 :
  340 DEFPROCheader
  350 FOR opt%=4 TO 6 STEP 2
  360   P%=&8000:O%=mem%
  370   [OPT opt%
  380   BRK:BRK:BRK:JMP Service
  390   EQUB &82:EQUB Copyright-&8000
  400   EQUB &00:EQUS title$
  410   .Copyright
  420   EQUB &00:EQUS "(C)":EQUS copy$:EQUB &00
  430   .Service
  440   PHA:CMP #13:BEQ Serv13:CMP #14:BEQ Serv14
  450   .ServQuit
  460   PLA:RTS
  470   .Serv13
  480   TYA:EOR #15:CMP &F4:BCC ServQuit        :\ Not this ROM
  490   LDA &F4:EOR #15:STA &F5
  500   LDA #Data AND 255:STA &F6               :\ Point to start of RFS data
  510   LDA #Data DIV 256:STA &F7
  520   BNE ServExit
  530   .Serv14Slow
  540   LDA (&F6),Y:TAY:LDA #1:JSR AddPTR       :\ Get single byte
  550   .ServExit
  560   PLA:LDA #0:RTS
  570   .Serv14
  580   LDA &F5:EOR #15:CMP &F4:BNE ServQuit    :\ Not this ROM
  590   LDY #0:\LDA &281:\BEQ Serv14Slow        :\ Demo, *FX1,0 to select slow call
  600   LDA &E2:AND #8:BNE Serv14Slow           :\ Cataloging
  610   LDA &C2:CMP #4:BNE Serv14Slow           :\ Not fetching data block
  620   LDA &27A:BPL Serv14lp0                  :\ No Tube, with CS from previous CMP
  630   LDA &B2:AND &B3:CMP #&FF:PHP            :\ CC=Tube, CS=I/O
  640   .Serv14lp
  650   PLP                                     :\ Get saved Tube/IO flag
  660   .Serv14lp0
  670   PHP:BCS Serv14io                        :\ Save Tube/IO flag, jump if I/O
  680   .Serv14tube
  690   LDA (&F6),Y:STA &FEE5                   :\ Send data to Tube data FIFO
  700   JSR Delay:JSR Delay                     :\ Inter-byte Tube delay
  710   INY:CPY &3C8:BNE Serv14tube
  720   BEQ Serv14Next
  730   .Serv14io
  740   LDA (&F6),Y:STA (&B0),Y                 :\ Copy data directly to memory
  750   INY:CPY &3C8:BNE Serv14io
  760   .Serv14Next
  770   TYA:JSR AddPTR:LDA #2:JSR AddPTR        :\ Step past data and CRC
  780   LDA &3C9:BEQ Serv14Finished             :\ Last block.hi=0, was last block
  790   INC &B1:INC &F7                         :\ Step to next data block
  800   LDA (&F6),Y:CMP #ASC"#":BNE Serv14Last  :\ Not short header, last block
  810   LDA #1                                  :\ Step past single header byte
  820   .Serv14Next2
  830   JSR AddPTR:BCC Serv14lp                 :\ Do next data block
  840   .Serv14Last
  850   INY:LDA (&F6),Y:BNE Serv14Last          :\ Step past filename
  860   TYA:CLC:ADC #11:TAY:LDA (&F6),Y:STA &3C8:\ Get final block length
  870   LDA #0:STA &3C9                         :\ Set top byte=0 to flag last block
  880   TYA:CLC:ADC #9                          :\ Prepare to point to final data block
  890   LDY #0:BEQ Serv14Next2                  :\ Jump to update pointer and fetch last block
  900   .Serv14Finished
  910   PLP:STA &BE:STA &BF:STA &C2             :\ CRC=Ok, Progress=Done
  920   LDA #&80:STA &BD:STA &3CA               :\ b7=last block
  930   JMP ServExit
  940   .AddPTR
  950   CLC:ADC &F6:STA &F6
  960   LDA &F7:ADC #0:STA &F7
  970   .Delay
  980   RTS
  990   .Data
 1000 ]NEXT
 1010 ENDPROC
 1020 :
 1030 DEFPROCadd
 1040 in%=0:A%=FNfile(in$,5):Load%=X%!2:Exec%=X%!6:Size%=X%!10:Attr%=X%!14
 1050 IF A%:IF O%-mem%+Size%>&3F00:PRINT"Not enough space":CLOSE#in%:in%=0:ENDPROC
 1060 IF A%=1:in%=OPENIN(in$)
 1070 IF in%=0:PRINT"File '"in$"' not found":ENDPROC
 1080 name$=LEFT$(name$,8):REM should be ,10
 1090 hdr0%=O%:Block%=0
 1100 REPEAT
 1110   hdr%=O%:BlkLen%=Size%:IF BlkLen%>256:BlkLen%=256
 1120   Flag%=0:IF Size%<257:Flag%=&80:IF Size%=0:Flag%=&C0
 1130   $O%="*"+name$:O%=O%+1+LENname$:?O%=0
 1140   O%!1=Load%:O%!5=Exec%:O%!9=Block%:O%!11=BlkLen%:O%?13=Flag%:O%!14=0:O%=O%+18
 1150   IF Block%=0 OR Flag%<>0:!crc=0:!addr=hdr%+1:!num=O%-hdr%-1:CALL crc16%:!O%=!crc:O%=O%+2 ELSE ?hdr%=ASC"#":O%=hdr%+1
 1160   PROCgbpb(4,in%,O%,BlkLen%,0)
 1170   !crc=0:!addr=O%:!num=BlkLen%:CALL crc16%
 1180   O%!BlkLen%=!crc:O%=O%+BlkLen%+2
 1190   Size%=Size%-BlkLen%:Block%=Block%+1
 1200 UNTIL Size%=0
 1210 hdr0%!(15+LENname$)=O%-mem%+&8000
 1220 !crc=0:!addr=hdr0%+1:!num=18+LENname$:CALL crc16%
 1230 hdr0%?(19+LENname$)=crc?0:hdr0%?(20+LENname$)=crc?1
 1240 hdr%!(15+LENname$)=O%-mem%+&8000
 1250 !crc=0:!addr=hdr%+1:!num=18+LENname$:CALL crc16%
 1260 hdr%?(19+LENname$)=crc?0:hdr%?(20+LENname$)=crc?1
 1270 CLOSE#in%:in%=0
 1280 ENDPROC
 1290 :
 1300 DEFFNfile(A$,A%):$name%=A$:?X%=name%:X%?1=name%DIV256:=(USR&FFDD)AND&FF
 1310 DEFPROCgbpb(A%,chn%,addr%,num%,ptr%):?X%=chn%:X%!1=addr%:X%!5=num%:X%!9=ptr%:CALL&FFD1:ENDPROC