10 REM > ROMCommand 1.01 05-Feb-2016 J.G.Harston
   20 REM Put a 6502 program into sideways ROM module
   30 REM NOTE Not suitable for *command that reads command parameters
   40 :
   50 DIM S% 500:T%=S%
   60 INPUT "6502 code file:   "in$
   70 INPUT "Output ROM file:  "fname$
   80 INPUT "Command name:     "cmd$
   90 INPUT "Version string:   "ver$
  100 INPUT "Copyright string: (C)"cpy$
  110 PROCp(in$):PROCp(fname$):PROCp(cmd$):PROCp(ver$):PROCp(cpy$)
  120 CLEAR:DIM S% T%-S%:PROCassem(0):CLEAR:DIM S% T%-S%:PROCassem(2):PROCsm_table
  130 A$="*SAVE "+fname$+" "+STR$~(mcode%+M%)+" "+STR$~O%+" FFFF0000 FFFBBC00"
  140 PRINTA$;:OSCLIA$:PRINT
  150 END
  160 :
  170 DEFPROCp(A$):$T%=A$:T%=T%+LEN$T%+1:ENDPROC
  180 DEFFNg:B%=T%:T%=T%+LEN$T%+1:=$B%
  190 DEFPROCassem(pass%)
  200 T%=S%:in$=FNg:fname$=FNg:cmd$=FNg:ver$=FNg:cpy$=FNg
  210 ver%=VALver$:IFMID$(ver$,2,1)=".":ver%=16*VALLEFT$(ver$,1)+VALMID$(ver$,3,1)
  220 DIM ctrl% 31,name% 31:X%=ctrl%:Y%=X%DIV256
  230 A%=FNfile(in$,5):IF A%=0:PRINT"File '"in$"' not found":END
  240 IF (X%!4 AND X%!8 AND &FFFF)<>&FFFF:PRINT"File '"in$"' is not I/O code":END
  250 load%=X%!2:exec%=X%!6:size%=X%!10
  260 DIM mcode% size%*2.5+300, L% -1
  270 OSWRCH=&FFE3:OSNEWL=&FFE7:OSBYTE=&FFF4:OS_CLI=&FFF7
  280 FOR pass%=pass% TO pass%+1
  290   opt%=FNsm_pass(pass%)+8+16
  300   [OPT opt%
  310   .RomStart
  320   BRK:EQUW RelocTable
  330   JMP Service
  340   EQUB &82:EQUB Copyright-RomStart
  350   .RomTitle
  360   EQUB ver%:EQUS cmd$
  370   EQUB &00 :EQUS ver$
  380   .Copyright
  390   EQUB &00:EQUS "(C)"+cpy$:EQUB 0
  400   :
  410   .Service
  420   CMP #4:BEQ Serv4          :\ *command
  430   CMP #9:BNE NotServ9       :\ Not *Help
  440   LDA (&F2),Y
  450   CMP #13:BNE Serv9Skip     :\ Not *Help <cr>
  460   JSR OSNEWL:LDX #0
  470   .Serv9Lp
  480   LDA RomTitle+1,X          :\ Print ROM title
  490   BNE P%+4:LDA #ASC" "      :\ Convert &00 to <spc>
  500   CMP #ASC"(":BEQ Serv9Done :\ End at '('
  510   JSR OSWRCH:INX:BNE Serv9Lp
  520   .Serv9Done
  530   JSR OSNEWL
  540   .Serv9Skip
  550   LDA #9
  560   .NotServ9
  570   RTS
  580   :
  590   .Serv4
  600   TYA:PHA:DEY:LDX #&FF
  610   .Serv4Lp
  620   INX:INY:LDA (&F2),Y
  630   CMP #ASC".":BEQ Serv4Dot
  640   CMP #ASC"!":BCC Serv4End
  650   CMP RomTitle+1,X:BEQ Serv4Lp :\ Match with ROM title
  660   EOR #&20                     :\ Change case
  670   CMP RomTitle+1,X:BEQ Serv4Lp :\ Match with ROM title
  680   .Serv4Quit
  690   PLA:TAY:LDA #4:RTS           :\ Restore Y, A and return unclaimed
  700   .Serv4End
  710   LDA RomTitle+1,X:BNE Serv4Quit
  720   DEY
  730   .Serv4Dot
  740   INY:PLA                      :\ Step past '.', balance stack
  750   JSR Serv4Call
  760   LDA #0:RTS                   :\ Return claimed
  770   :
  780   .Serv4Call
  790   LDA #(load% AND &00FF):STA &A8
  800   LDA #(load% AND &FF00) DIV 256:STA &A9
  810   LDY #0
  820   .TreeLp3
  830   LDA src,Y:STA &AA,Y
  840   INY:CPY #4:BCC TreeLp3
  850   TAY:BEQ TreeLp5:LDY #0
  860   .TreeLp4
  870   LDA (&AA),Y:STA (&A8),Y
  880   INY:BNE TreeLp4
  890   INC &A9:INC &AB
  900   DEC &AD:BNE TreeLp4
  910   .TreeLp5
  920   LDA (&AA),Y:STA (&A8),Y
  930   INY:CPY &AC:BCC TreeLp5
  940   JMP exec%
  950   :
  960   .src
  970   EQUW src+4:EQUW size%
  980   .file
  990   ]
 1000   IF O%+size%<L%:OSCLI"Load "+in$+" "+STR$~O% ELSE PRINT"Data overrun"
 1010   P%=P%+size%:O%=O%+size%:RelocTable=P%
 1020 NEXT:ENDPROC
 1030 :
 1040 DEFFNsm_pass(pass%)
 1050 IFpass%=0:M%=0
 1060 IFpass%=1:M%=O%-mcode%
 1070 P%=&8100-128*(pass%AND2)
 1080 O%=mcode%+M%*(pass%AND2)DIV2
 1090 IFpass%=1:IF O%+M%*2.125>L%:PRINT"Code overrun":END
 1100 =VALMID$("4646",pass%+1,1)
 1110 :
 1120 DEFPROCsm_table
 1130 base80%=mcode%+M%:base81%=mcode%:byte%=0:count%=0:off%=0:REPEAT
 1140   byte80%=base80%?off%:byte81%=base81%?off%:IF off%>=M%:byte80%=&80:byte81%=&80
 1150   IF ((byte81%-byte80%) AND &FE)<>0:PRINT "ERROR: Offset by more than one page at &";~&8000+off%
 1160   IF (byte80% AND &C0)=&80:byte%=byte%DIV2+128*(byte81%-byte80%):count%=count%+1
 1170   IF count%=8:?O%=byte%:O%=O%+1:byte%=0:count%=0
 1180 off%=off%+1:UNTILoff%>=M% AND count%=0
 1190 ENDPROC
 1200 :
 1210 DEFFNfile(A$,A%):$name%=A$:?X%=name%:X%?1=name%DIV256:=(USR&FFDD)AND&FF