10 REM > IDEDump 1.30
   20 REM Dump out sectors from IDE device
   30 REM v1.25 - Calculates missing b8-b15 of cylinder count
   40 REM v1.26 - Detects big-endian <size> in drive data
   50 REM v1.27 - move assem to end to ease cut/past from IDEPatch
   60 REM v1.28 - Tidied up display
   70 REM v1.29 - 16bit access uses 1x512 instead of 2x256
   80 REM v1.29a - FNstr() checked A%/A%?1 but outputted A%/A%?256 !!!
   90 REM v1.30 - Rearranged keys to allow "L"oad and "S"ave
  100 :
  110 M%=7
  120 IFFNfx(130,0)<>&FFFF:PRINT"Must be run in I/O processor":END
  130 ON ERROR VDU11:REPORT:PROCCloseAll:PRINTSPC9:END
  140 sz%=0:PROCasm:?IDEcommand=&08:REPEATUNTIL?IDEstatus<128:REM Initialise
  150 DIM ctrl% 31,data% &1FF:half%=0:MODEM%:mem%=data%:IFM%=7:mem%=&7C00
  160 sector%=1:cylinder%=0:head%=0:dev%=0:count%=1:PROCideSize(64,3)
  170 PROCHelp:REPEAT:PROCRead:REPEATPROCDisplay:REPEAT:X%=ctrl%:Y%=X%DIV256
  180       A$=GET$:IFA$>"_":A$=CHR$(ASCA$-32)
  190     UNTILINSTR("ITFZXCVNM,.WD07HLS ",A$)
  200     IFA$="I":PROCid
  210     REM IFA$="C":PROCcalc
  220     IFA$="T":PROCtest
  230     IFA$="F":half%=half%EOR&100
  240   UNTILINSTR("IT"+CHR$0,A$)=0
  250   IFA$="N":head%=(head%-1)AND3
  260   IFA$="M":head%=(head%+1)AND3
  270   IFA$=".":sector%=(sector%+1)AND255
  280   IFA$=",":sector%=(sector%-1)AND255
  290   IFA$="C":cylinder%=(cylinder%-1)AND&FFFF
  300   IFA$="V":cylinder%=(cylinder%+1)AND&FFFF
  310   IFA$="Z":lau%=(lau%-1)AND(lau%>1):PROCLAUtoCHS
  320   IFA$="X":lau%=(lau%+1)AND&FFFFFF:PROCLAUtoCHS
  330   IFA$="W":sz%=sz%EOR1:PROCHelp
  340   IFA$="D":dev%=dev%EOR1
  350   IFA$="0":M%=&80:MODEM%:PROCHelp:mem%=data%
  360   IFA$="7":M%=7:MODEM%:PROCHelp:mem%=&7C00
  370   IFA$=" ":INPUT" Go to sector: &"A$:PRINTCHR$11;SPC(38);CHR$13;:IFA$<>"":lau%=EVAL("&"+A$):PROCLAUtoCHS:A$=""
  380   IFA$=CHR$13:count%=count%+1
  390   IFA$="_":count%=count%-1
  400   IFA$="H":PROCcls:PROCHelp
  410   IFA$="S":PROCsave:CLS:PROCHelp
  420   IFA$="L":PROCload:CLS:PROCHelp
  430 UNTIL0:END
  440 :
  450 DEFPROCcls:IFM%=&80:ENDPROC
  460 PRINTTAB(0,17);:FORA%=1TO7:PRINTSPC(39):NEXT:PRINTSTRING$(7,CHR$11);:ENDPROC
  470 DEFPROCDisplay:PRINTTAB(8-(M%AND7),17-(M%AND3));
  480 PRINT"Sector:";FNh0(lau%,6);SPC2;"D:";dev%;SPC2;
  490 PRINT"C:"FNh0(cylinder%,4);SPC2;"H:"FNh0(head%,2);SPC2;"S:"FNh0(sector%,2)
  500 PRINT'SPC(16);CHR$13;:IFres%AND255:PRINT" Error: ";~res%
  510 IFM%=7:PRINTTAB(0,23);:ENDPROC
  520 PROCdump(mem%):PRINTTAB(0,23);:ENDPROC
  530 :
  540 DEFPROCHelp:PRINTTAB(7-(M%AND7),18-(M%AND3));
  550 PRINTFNd(sz%*8+8,3);"bit";SPC2;"<-ZX->    D  <-CV->  <NM>  <-->"'
  560 PRINT" <spc> Goto sector      W: Toggle width"
  570 PRINT" I: Investigate device  T: Test speed":IFM%=&80:PRINTTAB(40,20);
  580 PRINT" F: High/low 256 bytes  L: Load data":IFM%=&80:PRINTTAB(40,21);
  590 PRINT" ";7-(M%AND7);": Screen mode ";7-(M%AND7);"       S: Save data"
  600 IFM%=7:PRINTTAB(0,13);CHR$147;STRING$(38,",")'''''''
  610 ENDPROC
  620 :
  630 REM VDU13:PRINT"Status: &"FNh0(A%,4)"  Data: &"FNh0(!mem%,8)"  ";count%:IFM%=7:ENDPROC
  640 :
  650 DEFPROCdump(mem%)
  660 VDU30:FORA%=half% TO half%+255 STEP16
  670   PRINTFNh0(cylinder%,4)":"FNh0(head%,1)":"FNh0(sector%,2)" "FNh0(A%,4)" ";
  680   FOR B%=A% TO A%+15:PRINTFNh0(mem%?B%,2);" ";:NEXT
  690   FOR B%=A% TO A%+15:C%=mem%?B%:IFC%=127 OR C%<32:VDU46 ELSE VDUC%
  700   NEXT:IFA%<&1F0:PRINT
  710 NEXT:ENDPROC
  720 :
  730 DEFPROCRead:PROCCHStoLAU
  740 !addr%=mem%:sec%?2=lau%:sec%?1=(lau%AND&FF00)DIV256:sec%?0=(lau%AND&FF0000)DIV65536:?num%=count%:num%?1=sz%:res%=USRrd%
  750 ENDPROC
  760 :
  770 DEFPROCWrite:PROCCHStoLAU
  780 !addr%=mem%:sec%?2=lau%:sec%?1=(lau%AND&FF00)DIV256:sec%?0=(lau%AND&FF0000)DIV65536:?num%=1:num%?1=sz%:res%=USRwr%:ENDPROC
  790 :
  800 DEFPROCCHStoLAU:lau%=(sector%-1)+64*head%+256*cylinder%+dev%*&400000:ENDPROC
  810 :
  820 DEFPROCLAUtoCHS:sector%=(lau%AND63)+1:head%=(lau%AND&C0)DIV64:cylinder%=(lau%AND&3FFFFF)DIV256:ENDPROC
  830 :
  840 DEFFNh0(A%,N%)=RIGHT$("0000000"+STR$~A%,N%)
  850 DEFFNd(A%,N%)=RIGHT$("        "+STR$A%,N%)
  860 :
  870 DEFPROCid:LOCAL A%:PROCcls
  880 FOR A%=0 TO 255 STEP4:mem%!A%=0:mem%!(A%+256)=0:NEXT
  890 !addr%=mem%:A%=dev%*16:num%?1=sz%:CALL id%
  900 IFsz%=0:FOR A%=255 TO 0 STEP -1:mem%?(A%*2+1)=0:mem%?(A%*2)=mem%?A%:NEXT
  910 REM mem%?&75=mem%?&6E
  920 big%=FALSE:IFmem%?&74=0:big%=TRUE:mem%?&74=mem%?&72:mem%?&72=0
  930 IFmem%?&3+mem%?&6D+mem%?&73=0:mem%?&6D=mem%?&74:mem%?&73=mem%?&6C:tot%=(256*mem%?&6D+mem%?&6C)*mem%?&6E*mem%?&70:mem%?&3=(tot%DIV((mem%?6)*(mem%?12)))DIV256
  940 IFmem%?&79=0:mem%?&79=mem%?&6C
  950 PROCinfo:ENDPROC
  960 :
  970 DEFPROCinfo:PRINTTAB(0,24-(M%AND7));
  980 PRINT" Physical: C:&";FNhex(mem%+2);" H:";FNd(mem%?6,2);" S:";mem%?12
  990 PRINT" Logical:  C:&";FNhex(mem%+&6C);" H:";FNd(mem%?&6E,2);" S:";mem%?&70
 1000 tot%=mem%!&78:REM tot%=(256*mem%?&6D+mem%?&6C)*mem%?&6E*mem%?&70
 1010 tot%=mem%!&78
 1020 PRINT" Size:     &";FNhex(mem%+&7A);FNhex(mem%+&78);CHR$(32-10*big%);
 1030 IFmem%?&73+mem%?&75:PRINT;" ";tot%DIV4;"K";"  ";tot%DIV4096;"M ";CHR$127;
 1040 PRINT'" Serial:   "FNstr(mem%+20,10)
 1050 PRINT" Firmware: "FNstr(mem%+46,4)
 1060 PRINT" Model:    "FNstr(mem%+54,20)
 1070 ENDPROC
 1080 :
 1090 DEFPROCcalc:LOCAL A%,P%,L%:PROCid:size%=65536*mem%?116+mem%?114
 1100 matches%=0:log%=-1:PRINTTAB(0,27-(M%AND4));
 1110 FOR L%=0 TO 255:VDU11,11,11,11,11
 1120   PRINT"Logical:  C:&";FNh0(L%,2)'''''"Total    &";
 1130   tot%=(L%*256+mem%?&6C)*mem%?&6E*mem%?&70
 1140   PRINTFNh0(tot%,8);" ";tot%DIV4;"K";" ";tot%DIV4096;"M"
 1150   IF(tot%AND&00FF00FF)=size%:PRINT"Match at ";tot%DIV4096;"M";CHR$13;:matches%=matches%+1:log%=L%
 1160 VDU11:NEXT:PRINTSPC(38)'SPC(30);:VDU13,11
 1170 IFmatches%<>1:PRINT"Couldn't calculate size":ENDPROC
 1180 L%=log%:tot%=(L%*256+mem%?&6C)*mem%?&6E*mem%?&70
 1190 P%=tot%DIV((mem%?6)*(mem%?12)):mem%?3=P%DIV256:mem%?&6D=L%
 1200 mem%?&73=(tot%AND&FF00)DIV256:mem%?&75=(tot%AND&7F000000)DIV(&1000000)
 1210 PRINTSPC(20);CHR$13;:VDU11,11,11,11,11,11:PROCinfo
 1220 ENDPROC
 1230 :
 1240 DEFFNhex(A%):LOCAL A$:A$=FNh0(?A%,2)
 1250 IFA%?1:=FNh0(A%?1,2)+A$ ELSE ="xx"+A$
 1260 :
 1270 DEFFNstr(A%,N%):LOCAL A$:REPEAT
 1280   IFA%?1>31:A$=A$+CHR$A%?1 ELSE A$=A$+"."
 1290   IF?A%>31:A$=A$+CHR$?A% ELSE A$=A$+"."
 1300 A%=A%+2:N%=N%-1:UNTILN%<1:=A$
 1310 :
 1320 DEFPROCideInit:PROCideSize(64,3):ENDPROC
 1330 DEFPROCideSize(spt%,hds%)
 1340 ?&FC42=spt%:?&FC43=spt%
 1350 ?&FC46=hds%:?&FC47=&91:REM Initialise parameters
 1360 ENDPROC
 1370 :
 1380 DEFPROCrdMax
 1390 ?&FC46=0:?&FC47=&F8
 1400 REPEATUNTIL?&FC47<128
 1410 IF?&FC47 AND 1:IF ?&FC41 AND 4:PRINT"Not supported":ENDPROC
 1420 PRINT"Max: C:&";FNh0(?&FC45,2);FNh0(?&FC44,2);" H:";?&FC46 AND 15;" S:";?&FC43
 1430 ENDPROC
 1440 :
 1450 DEFPROCtest:PROCcls:PRINT"Test transfer speed";:max%=256
 1460 oldlau%=lau%:T%=TIME:FOR lau%=0 TO max%-1:!addr%=mem%:sec%?2=lau%:sec%?1=(lau%AND&FF00)DIV256:sec%?0=(lau%AND&FF0000)DIV65536:?num%=count%:num%?1=sz%:U%=TIME:A%=USRrd%:U%=TIME-U%:NEXT:T%=TIME-T%
 1470 VDU13:PRINT"Transfered ";max%*256*(sz%+1);" bytes in ";T%/100;"s"
 1480 PRINT"Speed:       ";max%*256*(sz%+1)DIV(T%/100);"cps over ";max%;" sectors"
 1490 PRINT"Burst speed: ";25600*(sz%+1)DIVU%;"cps per ";256*(sz%+1);" bytes"
 1500 lau%=oldlau%:VDU11,11,11:ENDPROC
 1510 :
 1520 DEFPROCwr:PROCcls:PRINT"Read/Write test - OVERWRITES DATA!":max%=256
 1530 FOR lau%=0 TO max%-1:PRINTCHR$13;"Reading "FNh0(lau%,8);
 1540   !addr%=mem%:sec%?2=lau%:sec%?1=(lau%AND&FF00)DIV256:sec%?0=(lau%AND&FF0000)DIV65536:?num%=count%:num%?1=sz%:A%=USRrd%:PRINT" - OK"
 1550   $mem%="*TEST* SECTOR &"+FNh0(lau%,8):PRINT"Writing "FNh0(lau%,8);
 1560   !addr%=mem%:sec%?2=lau%:sec%?1=(lau%AND&FF00)DIV256:sec%?0=(lau%AND&FF0000)DIV65536:?num%=count%:num%?1=sz%:A%=USRwr%:PRINT" - OK"
 1570   PRINT"Verifying "FNh0(lau%,8);
 1580   !addr%=mem%:sec%?2=lau%:sec%?1=(lau%AND&FF00)DIV256:sec%?0=(lau%AND&FF0000)DIV65536:?num%=count%:num%?1=sz%:A%=USRrd%
 1590   IF$mem%="*TEST* SECTOR &"+FNh0(lau%,8):PRINT" - OK":VDU11,11,11 ELSE PRINT" - Failed"
 1600 NEXT:ENDPROC
 1610 :
 1620 DEFFNsum:LOCAL sum%
 1630 FOR A%=0 TO 254:sum%=sum%+mem%?A%:IFsum%>255:sum%=(sum%+1)AND&FF
 1640 NEXT:=sum%AND&FF
 1650 :
 1660 DEFFNbyte(A%,X%,Y%)=((USR&FFF4)AND&FF00)DIV256
 1670 DEFFNfx(A%,X%):LOCAL Y%:Y%=X%DIV256:=((USR&FFF4)AND&FFFF00)DIV256
 1680 :
 1690 DEFPROCasm
 1700 mc%=mc%:IFmc%=0:DIMmc% 511
 1710 addr%=&80:sec%=&85:cmd%=&84:num%=&88:ptr%=&8E:res%=0
 1720 IDEdata=&FC40:IDEerror=&FC41:IDEcount=&FC42:IDEsector=&FC43
 1730 IDEcylinder=&FC44:IDEhead=&FC46:IDEstatus=&FC47:IDEcommand=&FC47
 1740 IF!IDEdata<>IDEdata!8:sz%=1
 1750 FORP=0 TO 1
 1760   P%=mc%:[OPT P*2
 1770   .id%
 1780   TAY:.idlp
 1790   LDA &FF:BMI idescape
 1800   LDA IDEstatus:BMI idlp
 1810   TYA:AND #16:STA IDEhead   :\ Device
 1820   LDA #&EC  :STA IDEcommand :\ &EC=Identify
 1830   LDY #0:LDX #1:STX num%
 1840   CLC:JMP TransferLoop
 1850   .idescape
 1860   RTS
 1870   :
 1880   .WaitForData
 1890   LDA &FC47:AND #8:BEQ WaitForData
 1900   LDA &FC47:RTS
 1910   :
 1920   .WaitNotBusy
 1930   PHP:JSR L806F                    :\ Get IDE status
 1940   AND #&80:BNE WaitNotBusy+1:PLP   :\ Wait for IDE not busy
 1950   BIT &CC:RTS
 1960   :
 1970   .L806F
 1980   PHP:LDA &FC47:STA &8D
 1990   LDA &FC47:CMP &8D:BNE L806F+1
 2000   PLP:RTS
 2010   :
 2020   .rd%:LDA #&08:STA cmd%:CLC:BCC CommandStart
 2030   .wr%:LDA #&0A:STA cmd%:SEC:BCS CommandStart
 2040   :
 2050   .CommandStart                           :\ C=R/W, ptr%=>block
 2060   LDA #addr%-1:STA ptr%:LDA #0:STA ptr%+1 :\ ptr%=>block
 2070   PHP:JSR SetGeometry:PLP
 2080   .CommandLoop
 2090   LDX #2:.Twice
 2100   JSR SetSector:LDY #0             :\ Set sector, count, command
 2110   .TransferLoop
 2120   JSR WaitForData:AND #&21:BNE TransError
 2130   \.TransferLoop
 2140   BIT &CD:\BVS TransTube:BCC IORead
 2150   :
 2160   .IOWrite
 2170   LDA num%+1:BEQ IOWrite8bit
 2180   INY:LDA (addr%),Y:STA &FC48:DEY
 2190   LDA (addr%),Y:STA &FC40
 2200   INC addr%:BNE P%+4:INC addr%+1
 2210   JMP TransferByte
 2220   .IOWrite8bit
 2230   LDA (addr%),Y:STA &FC40:JMP TransferByte
 2240   :
 2250   .IORead
 2260   LDA &FC40:STA (addr%),Y:LDA num%+1:BEQ TransferByte
 2270   INC addr%:BNE P%+4:INC addr%+1
 2280   LDA &FC48:STA (addr%),Y:JMP TransferByte
 2290   :
 2300   .TransferByte
 2310   LDA &FC47:AND #8:BEQ TransError  :\ Run out of data
 2320   INY:BNE TransferLoop             :\ Loop for 256 bytes/words
 2330   LDA &FC47:AND #&21:BNE TransError:\ Error occured
 2340   DEX:BEQ Next                     :\ Done twice, do next sector
 2350   LDA num%+1:BEQ Twice             :\ 8-bit, addr unchanged
 2360   DEC addr%+1:JMP Twice            :\ Step addr back, do second pass
 2370   :
 2380   .Next
 2390   INC sec%+2:BNE TransCount        :\ Increment sector
 2400   INC sec%+1:BNE TransCount:INC sec%
 2410   .TransCount
 2420   INC addr%+1:DEC num%:BNE CommandLoop     :\ Loop for all sectors
 2430   LDA #0                                   :\ Done, no errors
 2440   .TransError
 2450   LDX &FC47:LDA &FC41:RTS
 2460   :
 2470   .SetGeometry
 2480   JSR WaitNotBusy                          :\ Should check device
 2490   LDA #64:STA &FC42:STA &FC43              :\ 64 sectors per track
 2500   LDA sec%:LSR A:LSR A:ORA #3:AND #&13
 2510   STA &FC46:LDA #&91:STA &FC47      :\ 4 heads per cylinder
 2520   RTS
 2530   :
 2540   .SetSector
 2550   PHP:JSR WaitNotBusy                        :\ Save CC/CS Read/Write
 2560   LDY #8:LDA #1:STA &FC42                    :\ One sector
 2570   CLC:LDA (ptr%),Y:AND #63:ADC #1:STA &FC43  :\ Set sector b0-b5
 2580   DEY:LDA (ptr%),Y:STA &FC44                 :\ Set sector b8-b15
 2590   DEY:LDA (ptr%),Y:PHA:AND #&3F:STA &FC45    :\ Set sector b16-b20
 2600   PLA:ROL A:ROL A:ROL A:ROL A                :\ Get Drive 0/1
 2610   INY:INY:EOR (ptr%),Y:AND #&02:EOR (ptr%),Y :\ Merge Drive and Head
 2620   JSR SetDrive:DEY:DEY:DEY:LDA (ptr%),Y      :\ Get command &08 or &0A
 2630   .SetCommand
 2640   AND #2:PHA:EOR #2:LSR A:LSR A            :\ Copy ~b1 into Cy
 2650   PLA:ASL A:ASL A:ASL A:ORA #&20           :\ Translate CS->&20 or CC->&30
 2660   STA &FC47:PLP:RTS                        :\ Set command &08 or &0A
 2670   :
 2680   .SetDrive
 2690   ROL A:ROL A:ROL A:AND #&13:STA &FC46:RTS :\ Set device + sector b6-b7
 2700   :
 2710 ]NEXT:ENDPROC
 2720 DEFPROCCloseAll:in%=in%:IFin%:A%=in%:in%=0:CLOSE#A%
 2730 out%=out%:IFout%:A%=out%:out%=0:CLOSE#A%
 2740 ENDPROC
 2750 DEFPROCgbpb(A%,ch%,ad%,nm%,pt%):?X%=ch%:X%!1=ad%:X%!5=nm%:X%!9=pt%:CALL&FFD1:ENDPROC
 2760 DEFPROCsave:PROCcls:PRINT" Save data from IDE device"
 2770 INPUT" File to save to: "f$:INPUT" Start sector: &"s$:INPUT" Number of sectors: "n$:SC%=EVAL("&"+s$):NM%=VALn$:out%=OPENOUT(f$):REPEATPRINTCHR$13;" ";FNh0(SC%,6);
 2780   lau%=SC%:PROCLAUtoCHS:PROCRead:PROCgbpb(2,out%,mem%,256+256*sz%,0)
 2790 SC%=SC%+1:NM%=NM%-1:UNTILNM%<1:CLOSE#out%:out%=0:ENDPROC
 2800 DEFPROCload:PROCcls:PRINT" Load data to IDE device"
 2810 INPUT" File to load from: "f$:INPUT" Start sector: &"s$:SC%=EVAL("&"+s$):in%=OPENIN(f$):REPEATPRINTCHR$13;" ";FNh0(SC%,6);
 2820   lau%=SC%:PROCLAUtoCHS:PROCgbpb(4,in%,mem%,256+256*sz%,0):PROCWrite
 2830 SC%=SC%+1:UNTILEOF#in%:CLOSE#in%:in%=0:ENDPROC