uses dos, crt, helpers, fdc; const SEP = '--------------------------------------------------------------------------'; var tmp: TFDCBbuffer; drive: byte; i: integer; startTrack, maxTrack: byte; ff: file; tries, track, head, sector, sc: byte; out_file_name, d: string; fdcIOErrorBackup: byte; maxTries: byte; testMode, motorOffMethod, showDump: boolean; c: char; showDumpSector: byte; {----------------------------------------------------------------------------} function fdcGetSpeed(drv: byte): byte; var speed_id: byte; begin fdcGetSpeed:= 255; { speed unknown } for speed_id:= 0 to FDC_SPEED_COUNT do begin port[FDC_REG_DIR]:= speed_id; fdcReadSector(drv,0,0,1,FDC_SECTOR_1024,9); { ISDOS specific } if fdcIOError = FDC_OK then begin fdcGetSpeed:= speed_id; exit; end; end; fdcIOError:= FDC_ERR_SECTOR_NOT_FOUND; end; {----------------------------------------------------------------------------} function GetMaxTrack(param: string): byte; begin GetMaxTrack:= 79; if param[3] = '1' then GetMaxTrack:= 80; if param[3] = '2' then GetMaxTrack:= 81; if param[3] = '3' then GetMaxTrack:= 82; if param[3] = '4' then GetMaxTrack:= 83; if param[3] = '5' then GetMaxTrack:= 84; if length(param) = 2 then GetMaxTrack:= 82; end; {----------------------------------------------------------------------------} function GetMaxTries(param: string): byte; begin GetMaxTries:= 3; if param[3] = '4' then GetMaxTries:= 4; if param[3] = '5' then GetMaxTries:= 5; if param[3] = '6' then GetMaxTries:= 6; if param[3] = '7' then GetMaxTries:= 7; if param[3] = '8' then GetMaxTries:= 8; if param[3] = '9' then GetMaxTries:= 9; end; {----------------------------------------------------------------------------} begin ClrScr; drive:= 0; startTrack:= 0; maxTrack:= 79; out_file_name:= '_isdos.isd'; maxTries:= 5; testMode:= false; motorOffMethod:= false; showDump:= false; showDumpSector:= 1; {----------------------------------------------------------------------------} if ParamCount = 1 then begin d:= strlo(ParamStr(1)); { drive } if d = 'a:' then drive:= 0; if d = 'b:' then drive:= 1; end; if ParamCount > 1 then begin d:= strlo(ParamStr(1)); { drive } if d = 'a:' then drive:= 0; if d = 'b:' then drive:= 1; d:= strlo(ParamStr(2)); { out file name} if d[1] <> '/' then out_file_name:= d; end; for i:= 1 to ParamCount do begin d:= strlo(ParamStr(i)); if copy(d,1,2) = '/t' then begin testMode:= true; startTrack:= 80; maxTrack:= GetMaxTrack(d); continue; end; if copy(d,1,2) = '/m' then begin maxTrack:= GetMaxTrack(d); continue; end; if copy(d,1,2) = '/r' then begin maxTries:= GetMaxTries(d); continue; end; if copy(d,1,2) = '/o' then begin motorOffMethod:= true; continue; end; if copy(d,1,2) = '/d' then begin showDump:= true; if (length(d) = 3) and (d[3] = '1') then showDumpSector:= 1; if (length(d) = 3) and (d[3] = '2') then showDumpSector:= 2; if (length(d) = 3) and (d[3] = '3') then showDumpSector:= 3; if (length(d) = 3) and (d[3] = '4') then showDumpSector:= 4; if (length(d) = 3) and (d[3] = '5') then showDumpSector:= 5; if (length(d) = 3) and (d[3] = '6') then showDumpSector:= 6; if (length(d) = 3) and (d[3] = '7') then showDumpSector:= 7; if (length(d) = 3) and (d[3] = '8') then showDumpSector:= 8; if (length(d) = 3) and (d[3] = '9') then showDumpSector:= 9; continue; end; end; {----------------------------------------------------------------------------} writeln('ZX Spectrum Navigator v1.15 Reading iS-DOS floppy disk'); writeln('https://zxsn.ru, RomanRom2@gmail.com'); writeln('Copyright (c) 1996-2026 RomanRom2'); writeln(SEP); if strlo(ParamStr(1)) = '/h' then begin writeln('LD-ISDOS.EXE drive|key '); writeln(' - key /dN try to show dump of track 0 head 0 sector N'); writeln(' by default N=1, means /d is the same /d1'); writeln(' - key /o enable MotorOff method each 4,6,8 tries'); writeln(' - key /rN set max tries to read bad sector'); writeln(' by default N=5'); writeln(' - key /mN enable 8N tracks, N = 1..5 means 81-85 tracks'); writeln(' /m is the same /m3 for 83'); writeln('by default drive [A:], file name gets from disk name'); writeln(SEP); writeln('Examples:'); writeln('LD-ISDOS.EXE /m5 - dump disk A: names as DiskName with max tracks'); writeln('LD-ISDOS.EXE b: - dump disk B: names as DiskName'); writeln('LD-ISDOS.EXE a: MYDSK - dump disk A: names as MYDSK'); writeln('LD-ISDOS.EXE a: MYDSK /m2 - dump disk A: names as MYDSK with 82 tracks'); writeln('LD-ISDOS.EXE a: /d9 - dump disk A: names as DiskName with dump sector 9'); writeln('LD-ISDOS.EXE /d /r2 - dump disk A: names as DiskName with dump sector 1'); writeln(' and 2 retries to read bad sectors'); end else begin writeln('LD-ISDOS.EXE /h - for help'); end; writeln(SEP); writeln; if strlo(ParamStr(1)) = '/h' then exit; {----------------------------------------------------------------------------} writeln('Drive ',chr(drive+65),': is initializing...'); fdcInit(drive, FDC_SECTOR_1024); if fdcIOError <> FDC_OK then begin writeln('FDC init error ['+fdcErrorStr(fdcIOError)+']'); fdcRecalibrate(drive); fdcMotorOff; exit; end; writeln(fdcErrorStr(fdcIOError),', ',fdcSpeedStr(fdcGetSpeed(drive)));{} { do not show it in test mode } if not testMode then begin { check 1st sector for disk name } fdcReadSector(drive,0,0,1,FDC_SECTOR_1024,9); if fdcIOError <> FDC_OK then begin writeln('1st sector read error ['+fdcErrorStr(fdcIOError)+']'); fdcRecalibrate(drive); fdcMotorOff; exit; end; { get disk name } d:=''; for i:=1 to 8 do if fdcBuf[i+2]<>32 then d:=d+chr(fdcBuf[i+2]); if out_file_name = '_isdos.isd' then out_file_name:= hob2pc(d)+'.isd';; write('Disk name: [',d,']'); out_file_name:= CheckEx(out_file_name); writeln(' (',out_file_name,')'); if motorOffMethod then writeln('MotorOff method each 4,6,8 tries is enabled'); if showDump then begin { dump 1st sector } fdcReadSector(drive,0,0,showDumpSector,FDC_SECTOR_1024,9); writeln(SEP); for i:= 0 to 15 do begin for track:= 0 to 15 do begin gotoxy((track+1)*3,wherey); write(dec2hex(strr(fdcBuf[1+i*16+track]))); gotoxy(51+(track+1),wherey); if fdcBuf[1+i*16+track]>31 then write(chr(fdcBuf[1+i*16+track])) else write('.'); end; writeln; end; writeln(SEP); writeln('ESC - cancel, any key - continue'); c:= readkey; if c = #27 then begin writeln; writeln('Canceled.'); fdcRecalibrate(drive); fdcMotorOff; exit; end; end; writeln; writeln('Dumping ',maxTrack+1,' tracks...'); end else begin writeln; writeln('TEST [',startTrack,'..',maxTrack+1,'] TRACKS MODE'); end; {----------------------------------------------------------------------------} if not testMode then begin { do not dump in test mode } assign(ff, out_file_name); rewrite(ff, 1); end; for track:= startTrack to maxTrack do begin fdcSeek(drive, track); for head:= 0 to 1 do Begin for i:=1 to 5*1024 do tmp[i]:= 0; { empty buffer by zero } for sector:= 1 to 5 do begin if keypressed then break; sc:= sector; if sector = 5 then sc:= 9; write('Track:',track:2,' Head:',head:1,' Sector:',sc,' '); { mark sector as a bad sector } for i:=1 to 1024 do tmp[(sector-1)*1024+i]:= ord('B'); for tries:= 1 to maxTries do begin if keypressed then break; fdcReadSector(drive+(head shl 2),track,head,sc,FDC_SECTOR_1024,9); fdcIOErrorBackup:= fdcIOError; if fdcIOErrorBackup = FDC_OK then break; write('.'); if motorOffMethod then begin if tries in [4,6,8] then begin fdcMotorOff; delay(100); fdcMotorOn(drive); continue; end; end; if track > 4 then fdcSeek(drive, track-4) else fdcSeek(drive, 0); fdcSeek(drive,track); end; if fdcIOErrorBackup = FDC_ERR_BAD_SECTOR then write(fdcErrorStr(fdcIOErrorBackup)+' (saved) '+#13) else write(fdcErrorStr(fdcIOErrorBackup)+' '+#13); if fdcIOErrorBackup <> FDC_OK then writeln; { save buffer only if [OK] or [BAD_SECTOR] } if fdcIOErrorBackup in [FDC_OK, FDC_ERR_BAD_SECTOR] then for i:=1 to 1024 do tmp[(sector-1)*1024+i]:= fdcBuf[i]; end; { do not dump in test mode } if not testMode then BlockWrite(ff, tmp, 5*1024); { dump full track } End; if KeyPressed then if ReadKey = #27 then begin writeln(#13#10'... break pressed'); break; end; end; { do not dump in test mode } if not testMode then close(ff); fdcRecalibrate(drive); fdcMotorOff; write(#13' '); writeln(#13#10'Done.'#13#10); end.