10 REM > MkSrcZ80 - Make a Z80 source file
   20 REM > MkSrcCore v0.24 17-Apr-2020
   30 REM (C) J.G.Harston
   40 REM v0.10 16-Aug-2007 Original version
   50 REM v0.11 18-Mar-2008 Uses generic file functions
   60 REM v0.20 07-Jan-2011 Text output option
   70 REM v0.21 23-Feb-2011 Comment output selectable
   80 REM v0.22 28-Aug-2011 Comment width adapts to CPU
   90 REM v0.23 18-Aug-2014 MOS labels don't have trailing dump characters
  100 REM v0.24 17-Apr-2020 Fixed wrapping of long disassembly lines
  110 :
  120 A%=0:X%=1:os%=((USR&FFF4)AND&FF00)DIV256
  130 DIM ctrl% 79,name% 127:X%=ctrl%:Y%=X%DIV256:cpu%=0
  140 eol$=CHR$(10-3*(os%<6)):IFos%AND32:eol$=CHR$13+CHR$10
  150 :
  160 ON ERROR REPORT:PROCClose_All:PRINT:END
  170 INPUT"Input object file:       "in$
  180 IFFNfile(in$,5)<>1:PRINT"File '"in$"' not found":END
  190 len%=X%!10:IF HIMEM-TOP-2000<len%:PRINT"File '"in$"' too long":END
  200 load%=X%!2:exec%=X%!6:DIM mem% len%:OSCLI"LOAD """+in$+""" "+STR$~mem%
  210 INPUT"Output source file:      "out$:out%=0:IFout$<>"":out%=OPENOUT(out$)
  220 A%=load%AND&FFFFFF00
  230 IF A%=&FFF70000:load%=&0000:exec%=&0000           :REM Spectrum ROM
  240 IF A%=&FFFBBC00:load%=&8000:exec%=&8000:IF mem%!0=0:IF mem%!4=0:load%=&C000:exec%=&C000:REM BBC ROM
  250 IF A%=&FFFFF800:load%=&8000:exec%=&8000           :REM Absolute
  260 IF A%=&FFFFFA00:load%=&0000:exec%=&0000           :REM Module
  270 IF A%=&FFFFFC00:load%=&0000:exec%=&0000           :REM Utility
  280 PRINT"Disassembly address:     (&";~load%;:INPUT") &"A$:IFA$<>"":load%=EVAL("&"+A$):exec%=load%
  290 REPEAT:X%!0=0:A$=FNDis_Name(cpu%):IF A$="":INPUT "CPU number:"SPC11;""cpu%
  300 UNTILA$<>"":dat%=X%?3AND12:wth%=(X%?3AND3)*2+4:mask%=EVAL("&"+STRING$(wth%,"F"))
  310 IFdat%=0:dat%=wth%+12 ELSE IFdat%=12:dat%=21 ELSE dat%=9
  320 INPUT"(B)asic or (T)ext output?        "A$:text%=(LEFT$(A$,1)="T" OR LEFT$(A$,1)="t")
  330 INPUT"Output byte dump in comments?    "A$:cmmt%=(LEFT$(A$,1)="Y" OR LEFT$(A$,1)="y")
  340 INPUT"Output byte dump in disassembly? "A$:dump%=(LEFT$(A$,1)="Y" OR LEFT$(A$,1)="y")
  350 cmmt%=cmmt%ORdump%
  360 :
  370 FOR B%=0 TO 1:addr%=load%:lbmax%=0
  380   IF B%:PRINT "Creating labels";STRING$(7+wth%,"."); ELSE PRINT "Scanning for labels";STRING$(3+wth%,".");
  390   REPEAT:PRINT STRING$(wth%,CHR$8);FNh0(addr%,wth%);:L$=FNline:A%=INSTR(L$,"&")
  400     IF A%:IF MID$(L$,A%+1,1)>="0":L%=EVALMID$(L$,A%):IF L%>&FF:IF L%>=(load%ANDmask%) AND L%<(load%ANDmask%)+len%:lbmax%=lbmax%+4:IF B%:!lb%=L%:lb%=lb%+4
  410   addr%=addr%+num%:UNTIL addr%>load%+len%:IF B%=0:DIM label% lbmax%:lb%=label%
  420 PRINT:NEXT B%
  430 :
  440 PRINT "Outputting source.....";FNh0(load%,wth%);
  450 PROCout("REM",CHR$&F4+" > "+out$)
  460 PROCout("REM",CHR$&F4+" Source for "+in$)
  470 PROCout(""," ")
  480 PROCout("","OS_CLI=&FFF7:OSBYTE=&FFF4:OSWORD=&FFF1:OSWRCH=&FFEE")
  490 PROCout("","OSWRCR=&FFEC:OSNEWL=&FFE7:OSASCI=&FFE3:OSRDCH=&FFE0")
  500 PROCout("","OSFILE=&FFDD:OSARGS=&FFDA:OSBGET=&FFD7:OSBPUT=&FFD4")
  510 PROCout("","OSGBPB=&FFD1:OSFIND=&FFCE")
  520 PROCout(""," ")
  530 PROCout("","load%=&"+STR$~load%)
  540 PROCout("DIM",CHR$&DE+" mcode% &"+STR$~(len%+20))
  550 IF text%:PROCout("","FOR P=0 TO 1"ELSE PROCout("",CHR$&E3+" P=0 "+CHR$&B8+" 1")
  560 PROCout("","P%=load%:O%=mcode%")
  570 PROCout("","[OPT P*3+4")
  580 :
  590 addr%=load%:REPEAT:PRINT STRING$(wth%,CHR$8);FNh0(addr%,wth%);:L$=FNline:IF addr%=exec%:PROCout("",".exec%")
  600   lb%=label%-4:REPEAT lb%=lb%+4:UNTIL lb%>label%+lbmax% OR !lb%=(addr%ANDmask%):IF !lb%=(addr%ANDmask%):PROCout("",".L"+FNh0(addr%ANDmask%,wth%))
  610   A$="":A%=INSTR(L$,"&"):IF A%:IF MID$(L$,A%+1,1)>="0":L%=EVALMID$(L$,A%):IF L%>=(load%ANDmask%) AND L%<(load%ANDmask%)+len%:L$=LEFT$(L$,A%-1)+"L"+MID$(L$,A%+1)
  620   IF cmmt%:A$=FNh0(addr%,wth%):B$="":FOR A%=0 TO num%-1:B%=?(addr%-load%+mem%+A%):A$=A$+" "+FNh0(B%,2):B$=B$+FNch(B%):NEXT:A$=A$+STRING$((dat%-LENA$)AND(LENA$<dat%)," ")+" "+B$
  630   IF dump%:IF LENA$<dat%+5:A$=A$+STRING$(dat%+5-LENA$," ")
  640   IF cmmt%:IF dump%=0:PROCout("",L$+STRING$((20-LENL$)AND(LENL$<20)," ")+" :\ "+A$)
  650   IF cmmt%:IF dump%:PROCout("",A$+" : "+L$)
  660   IF cmmt%=0:PROCout("",L$)
  670   IF (flg%AND64):PROCout(""," ")
  680 addr%=addr%+num%:UNTILaddr%>load%+len%
  690 :
  700 IF text%:PROCout("","]NEXT"ELSE PROCout("","]"+CHR$&ED)
  710 PROCout("PRINT",CHR$&F1+" ""*SAVE <file> "";~mcode%;"" "";~O%;"" "";~exec%;"" "";~load%")
  720 IF out%:IF NOTtext%:BPUT#out%,13:BPUT#out%,255
  730 IF out%:CLOSE#out%:out%=0:X%!2=&FFFFFB00-1024*text%:A%=FNfile(out$,2)
  740 PRINT:END
  750 :
  760 DEFFNline:num%=FNDis_Code(cpu%,addr%,addr%-load%+mem%):L$=$(X%+4)
  770 num%=X%?3:flg%=X%?2:A%=INSTR(L$,"&FF"):IFA%=0:=L$
  780 L%=EVAL(MID$(L$,A%,5))-&FFCE:IFL%<0 OR L%>43:=L$
  790 IF((L%MOD3-(L%>27))MOD3-3*(L%=24)+(L%>24 AND L%<28)-3*(L%=27)-(L%=28)):=L$
  800 =LEFT$(L$,A%-1)+"OS"+MID$("FINDGBPBBPUTBGETARGSFILERDCHASCINEWLWRCRWRCHWORDBYTE_CLI",(L%DIV3)*4+1,4)+MID$(L$,A%+5)
  810 :
  820 DEFPROCout(T$,A$):IFout%=0:ENDPROC
  830 IFtext%:A$=T$+MID$(A$,(T$="")+2)+eol$:$name%=A$:PROCgbpb(2,out%,name%,LENA$,0):ENDPROC
  840 line%=line%+1:?name%=13:name%?1=line%DIV256:name%?2=line%
  850 name%?3=LENA$+4:$(name%+4)=A$:PROCgbpb(2,out%,name%,LENA$+4,0):ENDPROC
  860 :
  870 DEFPROCClose_All:out%=out%:IFout%:A%=out%:out%=0:CLOSE#A%
  880 ENDPROC
  890 :
  900 DEFFNch(A%):A%=A%AND127:IFA%<32 OR A%=127:="." ELSE =CHR$A%
  910 DEFFNh0(A%,N%)=RIGHT$("0000000"+STR$~A%,N%)
  920 DEFPROCgbpb(A%,chn%,addr%,num%,ptr%)
  930 ?X%=chn%:X%!1=addr%:X%!5=num%:X%!9=ptr%:IF(os%AND32)=0:CALL&FFD1:ENDPROC
  940 IFA%=1ORA%=3:PTR#?X%=X%!9
  950 REPEAT:IFA%=1ORA%=2:BPUT#?X%,?X%!1 ELSE IFA%=3ORA%=4:?X%!1=BGET#?X%
  960 X%!1=X%!1+1:X%!5=X%!5-1:UNTIL(EOF#?X% AND A%>2)OR X%!5<1:ENDPROC
  970 DEFFNfile(A$,A%):IF(os%AND32)=0:$name%=A$:?X%=name%:X%?1=name%DIV256:=(USR&FFDD)AND&FF
  980 IFA%=5:X%!14=OPENIN(A$):IFX%!14:X%!10=EXT#X%!14:CLOSE#X%!14:X%!2=0:X%!6=0:X%!14=&33:=1
  990 =0
 1000 :
 1010 REM > DisZ80 1.01 - 09-Jan-1989 - Z80 disassembly routines
 1020 :
 1030 DEFFNDis_Name(A%)="Z80"
 1040 DEFFNDis_Code(A%,Ptr%,Data%):LOCAL s%,d%,c%,xy%:!X%=0:num%=1:c%=?Data%
 1050 d%=c%AND7:s%=(c%AND&38)DIV8:$(X%+4)=EVAL("FNz80_"+STR$~(c%AND&C0))
 1060 X%?3=num%:=num%
 1070 :
 1080 DEFFNalu(A%)=MID$("ADDADCSUBSBCANDXOROR CP ",A%*3+1,3)
 1090 DEFFNrot(A%)=MID$("RLCRRCRL RR SLASRASLSSRL",A%*3+1,3)
 1100 DEFFNr(A%)=MID$("BCDEHLFA",A%+1,1)
 1110 DEFFNdrg(A%)=MID$("BCDEHLSPIXAFIY",(A%OR1)+((xy%*4)AND((A%AND6)=4)),2)
 1120 DEFFNreg(A%):IFxy%=0 AND A%<>6:=FNr(A%)
 1130 IFA%=6 AND xy%=0:="(HL)"
 1140 IFA%=6:num%=num%+1:="(I"+CHR$(87+xy%)+FNrel(Data%?2)+")"
 1150 IF(A%AND6)=4:="I"+CHR$(87+xy%)+FNr(A%)
 1160 =FNr(A%)
 1170 DEFFNrel(A%):IFA%<128:="+"+STR$A% ELSE =STR$(A%-256)
 1180 DEFFNjr(A%):IFA%<128:="&"+FNh0(Ptr%+A%+2,4) ELSE ="&"+FNh0(Ptr%+A%+2-256,4)
 1190 DEFFNcc(A%)=MID$("NZZ NCC POPEP M ",A%*2+1,2-((A% AND 1) AND (A%<4))-(1 AND (A%>5)))
 1200 :
 1210 DEFFNz80_0:IFc%=0:="NOP"
 1220 IF(c%AND&F7)=&10:num%=2:=MID$("DJNZJR  ",s%*4-7,4)+" "+FNjr(Data%?1)
 1230 IFd%=7 AND s%<4:=LEFT$(FNrot(s%),3+(s%>1))+"A"
 1240 IFd%=7:=MID$("DAACPLSCFCCF",s%*3-11,3)
 1250 IFd%=6:num%=num%+1:="LD   "+FNreg(s%)+",&"+FNh0(?(Data%+num%-1),2)
 1260 IF(d%AND6)=4:=MID$("INCDEC",(d%AND1)*3+1,3)+"  "+FNreg(s%)
 1270 IFd%=3:=MID$("INCDEC",(s%AND1)*3+1,3)+"  "+FNdrg(s%)
 1280 IFc%=&22:num%=num%+2:="LD   (&"+FNh0(!(Data%+num%-2),4)+"),"+FNdrg(4)
 1290 IFc%=&2A:num%=num%+2:="LD   "+FNdrg(4)+",(&"+FNh0(!(Data%+num%-2),4)+")"
 1300 IFc%=&32:num%=num%+2:="LD   (&"+FNh0(Data%!1,4)+"),A"
 1310 IFc%=&3A:num%=num%+2:="LD   A,(&"+FNh0(Data%!1,4)+")"
 1320 IFd%=2 AND (s%AND5)=0:="LD   ("+FNdrg(s%)+"),A"
 1330 IFd%=2:="LD   A,("+FNdrg(s%)+")"
 1340 IFd%=1 AND (s%AND1)=1:="ADD  "+FNdrg(4)+","+FNdrg(s%)
 1350 IFd%=1:num%=num%+2:="LD   "+FNdrg(s%)+",&"+FNh0(!(Data%+num%-2),4)
 1360 IFd%=0 AND s%>3:num%=num%+1:="JR   "+FNcc(s%AND3)+","+FNjr(Data%?1)
 1370 ="EX   AF,AF'"
 1380 :
 1390 DEFFNz80_40:IFc%=&76:="HALT"
 1400 IF s%=6:="LD   "+FNreg(s%)+","+FNr(d%)
 1410 IF d%=6:="LD   "+FNr(s%)+","+FNreg(d%)
 1420 ="LD   "+FNreg(s%)+","+FNreg(d%)
 1430 :
 1440 DEFFNz80_80:=FNalu(s%)+"  "+LEFT$("A,",s%<2 OR s%=3)+FNreg(d%)
 1450 DEFFNz80_C0:IFd%=5 AND (s%AND1)=1:=EVAL("FNz80_"+STR$~c%)
 1460 IFc%=&CB:=FNz80_CB
 1470 IFd%=7:="RST  &"+FNh0(c%AND&38,2)
 1480 IFd%=6 AND s%<4:num%=2:=FNalu(s%)+"  A,&"+FNh0(Data%?1,2)
 1490 IFd%=6:num%=2:=FNalu(s%)+"  &"+FNh0(Data%?1,2)
 1500 IF(d%AND3)=1 AND(s%AND1)=0:=MID$("POP PUSH",(d%DIV4)*4+1,4)+" "+FNdrg(s%-4*(s%>5))
 1510 IFd%=4:num%=num%+2:="CALL "+FNcc(s%)+",&"+FNh0(Data%!1,4)
 1520 IFd%=2:num%=num%+2:="JP   "+FNcc(s%)+",&"+FNh0(Data%!1,4)
 1530 IFd%=0:="RET  "+FNcc(s%)
 1540 IFc%=&C3:num%=3:="JP   &"+FNh0(Data%!1,4)
 1550 IFc%=&C9:="RET"
 1560 IFc%=&D3:num%=2:="OUT  (&"+FNh0(Data%?1,2)+"),A"
 1570 IFc%=&DB:num%=2:="IN   A,(&"+FNh0(Data%?1,2)+")"
 1580 IFc%=&D9:="EXX"
 1590 IFc%=&E3:="EX   (SP),"+FNdrg(4)
 1600 IFc%=&E9:="JP   ("+FNdrg(4)+")"
 1610 IFc%=&EB:="EX   DE,HL"
 1620 IFc%=&F9:="LD   SP,HL"
 1630 =MID$("DIEI",(s%AND1)*2+1,2)
 1640 :
 1650 DEFFNz80_CD:num%=3:="CALL &"+FNh0(Data%!1,4)
 1660 DEFFNz80_CB:num%=num%+1:IFxy%:c%=Data%?3 ELSE c%=Data%?1
 1670 d%=c%AND7:s%=(c%AND&38)DIV8:IFc%<&40:=FNrot(s%)+"  "+FNreg(d%)
 1680 =MID$("BITRESSET",(c%DIV64)*3-2,3)+"  "+STR$(s%)+","+FNreg(d%)
 1690 :
 1700 DEFFNz80_DD
 1710 DEFFNz80_FD
 1720 IFxy%:num%=1:="DEFB &"+FNh0(xy%*&20+&BD,2)
 1730 LOCAL A$:xy%=(c%AND&20)DIV&20+1:num%=num%+1
 1740 c%=Data%?1:d%=c%AND7:s%=(c%AND&38)DIV8:A$=EVAL("FNz80_"+STR$~(c%AND&C0))
 1750 IFINSTR(MID$(A$,4),"X")+INSTR(A$,"Y")=0:num%=1:="DEFB &"+FNh0(xy%*&20+&BD,2) ELSE =A$
 1760 :
 1770 DEFFNz80_ED:IFxy%:num%=1:="DEFB &"+FNh0(xy%*&20+&CD,2)
 1780 num%=num%+1:c%=Data%?1:d%=c%AND7:s%=(c%AND&38)DIV8
 1790 IFc%<&10:="DEFW &"+FNh0(c%*256+&ED,4)+":\ MOS_"+MID$("QUITCLI BYTEWORDWRCHRDCHFILEARGSBGETBPUTGBPBFINDFF0CFF0DFF0EFF0F",c%*4+1,4)
 1800 IFc%<&40 ORc%>&C0:num%=1:="DEFB &ED"
 1810 IF(c%AND&C7)=&42:=FNalu(3-(s%AND1)*2)+"  HL,"+FNdrg(s%)
 1820 IF(c%AND&CF)=&4B:num%=num%+2:="LD   "+FNdrg(s%)+",(&"+FNh0(Data%!2,4)+")"
 1830 IF(c%AND&CF)=&43:num%=num%+2:="LD   (&"+FNh0(Data%!2,4)+"),"+FNdrg(s%)
 1840 IF(c%AND&C7)=&40:="IN   "+FNr(s%)+",(C)"
 1850 IF(c%AND&C7)=&41:="OUT  (C),"+FNr(s%)
 1860 IF(c%AND&E7)=&46 ANDs%<>1:="IM   "+STR$(s%-1-(s%=0))
 1870 IF(c%AND&F7)=&67:=MID$("RRDRLD",s%*3-11,3)
 1880 IF(c%AND&F7)=&45:=MID$("RETNRETI",s%*4+1,4)
 1890 IFc%=&44:="NEG"
 1900 IF(c%AND&E7)=&47:="LD   "+CHR$(65-8*(s%=0)-17*(s%=1))+","+CHR$(65-8*(s%=2)-17*(s%=3))
 1910 IF(c%AND&E4)=&A0:=MID$("LDCPINOT",d%*2+1,2)+CHR$(73-5*(s%AND1))+CHR$(32+25*(s%AND2))
 1920 num%=1:="DEFB &ED"