(* D64.PAS -- access (c1541 and c1571) disk images ** Copyright (c) 1995,1996 Jochen Metzinger ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *) UNIT d64; INTERFACE CONST DISK_SIZE = 683; (* blocks on a single sided disk *) TYPE BLOCK = ARRAY [0..255] OF BYTE; (* sector on disk image *) PROCEDURE d64_open(filename: STRING); (* open image file *) PROCEDURE d64_close; (* close image file *) PROCEDURE d64_read(tr, sk: BYTE; VAR sector: BLOCK); (* read block at tr/sk *) PROCEDURE d64_write(tr, sk: BYTE; VAR sector: BLOCK); (* write block to tr/sk *) FUNCTION d64_double_sided: BOOLEAN; (* is image double sided? *) FUNCTION d64_read_only: BOOLEAN; (* is image disk read only? *) IMPLEMENTATION USES global, errors; TYPE geometry_entry = RECORD first, last: BYTE; blocks, offs: LongInt; END; (* geometry_entry *) CONST geometry: ARRAY [1..4] OF geometry_entry = ((first: 01; last: 17; blocks: 21; offs: 000), (first: 18; last: 24; blocks: 19; offs: 357), (first: 25; last: 30; blocks: 18; offs: 490), (first: 31; last: 35; blocks: 17; offs: 598)); VAR image: FILE OF BLOCK; double_sided, read_only: BOOLEAN; FUNCTION d64_double_sided: BOOLEAN; BEGIN d64_double_sided := double_sided; END; (* d64_double_sided *) FUNCTION d64_read_only: BOOLEAN; BEGIN d64_read_only := read_only; END; (* d64_read_only *) PROCEDURE d64_open(filename: STRING); VAR BAM: BLOCK; file_size: LongInt; BEGIN (*$I-*) Assign(image, AddExt(filename,'.d64')); Reset(image); read_only := (IOResult <> 0); IF read_only THEN BEGIN FileMode := FileMode_RO; Reset(image); FileMode := FileMode_RW; IF IOResult <> 0 THEN BEGIN error('open file'); EXIT; END; (* if *) END; (* if *) (*$I+*) file_size := FileSize(image); double_sided := (file_size = 2*DISK_SIZE); IF NOT double_sided THEN IF file_size <> DISK_SIZE THEN BEGIN Close(image); error('neither c1541 nor c1571 image [size]'); EXIT; END; (* if *) d64_read(18,0,BAM); err_stop; IF (BAM[2] <> $41) OR (BAM[165] <> $32) OR (BAM[166] <> $41) THEN BEGIN Close(image); error('neither c1541 nor c1571 image [BAM]'); EXIT; END; (* if *) END; (* d64_open *) PROCEDURE d64_close; BEGIN Close(image); END; (* d64_close *) FUNCTION d64_position(tr, sk: BYTE): LongInt; VAR side_offs: LongInt; zone: 1..4; BEGIN d64_position := -1; IF (tr = 0) OR (tr > 70) THEN EXIT; IF tr <= 35 THEN side_offs := 0 ELSE BEGIN IF NOT double_sided THEN EXIT; side_offs := DISK_SIZE; Dec(tr, 35); END; (* else *) FOR zone := 1 TO 4 DO WITH geometry[zone] DO IF tr <= last THEN BEGIN IF sk >= blocks THEN EXIT; d64_position := side_offs + offs + blocks*(tr - first) + sk; EXIT; END; (* if *) END; (* d64_position *) PROCEDURE d64_seek(tr, sk: BYTE); VAR pos: LongInt; BEGIN pos := d64_position(tr, sk); IF pos < 0 THEN BEGIN error('illegal track and sector '+long2str(tr,0)+' '+long2str(sk,0)); EXIT; END; (* if *) (*$I-*) Seek(image, pos); IF IOResult <> 0 THEN FATAL('seek'); (*$I+*) END; (* d64_seek *) PROCEDURE d64_read(tr, sk: BYTE; VAR sector: BLOCK); BEGIN d64_seek(tr,sk); IF is_err THEN EXIT; (*$I-*) Read(image,sector); IF IOResult <> 0 THEN FATAL('read'); (*$I+*) END; (* d64_read *) PROCEDURE d64_write(tr, sk: BYTE; VAR sector: BLOCK); BEGIN d64_seek(tr,sk); IF is_err THEN EXIT; (*$I-*) Write(image,sector); IF IOResult <> 0 THEN error('write'); (*$I+*) END; (* d64_write *) BEGIN double_sided := FALSE; read_only := TRUE; END. (* d64 *)