ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/1541d64.cpp
Revision: 1.7
Committed: 2004-01-12T14:58:26Z (20 years, 2 months ago) by cebix
Branch: MAIN
Changes since 1.6: +31 -1 lines
Log Message:
restored debugging code

File Contents

# Content
1 /*
2 * 1541d64.cpp - 1541 emulation in disk image files (.d64/.x64/zipcode)
3 *
4 * Frodo (C) 1994-1997,2002-2003 Christian Bauer
5 * zipcode decoding routines (C) 1993-1997 Marko Mäkelä, Paul David Doherty
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 /*
23 * Incompatibilities:
24 * - No support for relative files
25 * - Unimplemented commands: P
26 * - Impossible to implement: B-E, M-E
27 */
28
29 #include "sysdeps.h"
30
31 #include "1541d64.h"
32 #include "IEC.h"
33 #include "Prefs.h"
34 #include "C64.h"
35 #include "main.h"
36
37 #define DEBUG 0
38 #include "debug.h"
39
40
41 // Channel modes (IRC users listen up :-)
42 enum {
43 CHMOD_FREE, // Channel free
44 CHMOD_COMMAND, // Command/error channel
45 CHMOD_DIRECTORY, // Reading directory, using large allocated buffer
46 CHMOD_FILE, // Sequential file open, using buffer in 1541 RAM
47 CHMOD_REL, // Relative file open, using buffer in 1541 RAM
48 CHMOD_DIRECT // Direct buffer access ('#'), using buffer in 1541 RAM
49 };
50
51 // Directory track
52 const int DIR_TRACK = 18;
53
54 // BAM structure
55 enum {
56 BAM_DIR_TRACK = 0, // Track...
57 BAM_DIR_SECTOR = 1, // ...and sector of first directory block (unused)
58 BAM_FMT_TYPE = 2, // Format type
59 BAM_BITMAP = 4, // Sector allocation map
60 BAM_DISK_NAME = 144, // Disk name
61 BAM_DISK_ID = 162, // Disk ID
62 BAM_FMT_CHAR = 165 // Format characters
63 };
64
65 // Directory structure
66 enum {
67 DIR_NEXT_TRACK = 0, // Track...
68 DIR_NEXT_SECTOR = 1, // ... and sector of next directory block
69 DIR_ENTRIES = 2, // Start of directory entries (8)
70
71 DE_TYPE = 0, // File type/flags
72 DE_TRACK = 1, // Track...
73 DE_SECTOR = 2, // ...and sector of first data block
74 DE_NAME = 3, // File name
75 DE_SIDE_TRACK = 19, // Track...
76 DE_SIDE_SECTOR = 20, // ...and sector of first side sector
77 DE_REC_LEN = 21, // Record length
78 DE_OVR_TRACK = 26, // Track...
79 DE_OVR_SECTOR = 27, // ...and sector on overwrite (@)
80 DE_NUM_BLOCKS_L = 28, // Number of blocks, LSB
81 DE_NUM_BLOCKS_H = 29, // Number of blocks, MSB
82
83 SIZEOF_DE = 32 // Size of directory entry
84 };
85
86 // Interleave of directory and data blocks
87 const int DIR_INTERLEAVE = 3;
88 const int DATA_INTERLEAVE = 10;
89
90 // Number of sectors per track, for all tracks
91 const int num_sectors[41] = {
92 0,
93 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,
94 19,19,19,19,19,19,19,
95 18,18,18,18,18,18,
96 17,17,17,17,17,
97 17,17,17,17,17 // Tracks 36..40
98 };
99
100 // Accumulated number of sectors
101 const int accum_num_sectors[41] = {
102 0,
103 0,21,42,63,84,105,126,147,168,189,210,231,252,273,294,315,336,
104 357,376,395,414,433,452,471,
105 490,508,526,544,562,580,
106 598,615,632,649,666,
107 683,700,717,734,751 // Tracks 36..40
108 };
109
110 // Prototypes
111 static bool match(const uint8 *p, int p_len, const uint8 *n);
112
113
114 /*
115 * Constructor: Prepare emulation, open image file
116 */
117
118 ImageDrive::ImageDrive(IEC *iec, const char *filepath) : Drive(iec), the_file(NULL), bam(ram + 0x700), bam_dirty(false)
119 {
120 for (int i=0; i<18; i++) {
121 ch[i].mode = CHMOD_FREE;
122 ch[i].buf = NULL;
123 }
124 ch[15].mode = CHMOD_COMMAND;
125
126 Reset();
127
128 // Open image file
129 if (change_image(filepath))
130 Ready = true;
131 }
132
133
134 /*
135 * Destructor
136 */
137
138 ImageDrive::~ImageDrive()
139 {
140 close_image();
141 }
142
143
144 /*
145 * Close the image file
146 */
147
148 void ImageDrive::close_image(void)
149 {
150 if (the_file) {
151 close_all_channels();
152 if (bam_dirty) {
153 write_sector(DIR_TRACK, 0, bam);
154 bam_dirty = false;
155 }
156 fclose(the_file);
157 the_file = NULL;
158 }
159 }
160
161
162 /*
163 * Open the image file
164 */
165
166 bool ImageDrive::change_image(const char *path)
167 {
168 // Close old image file
169 close_image();
170
171 // Open new image file (try write access first, then read-only)
172 write_protected = false;
173 the_file = open_image_file(path, true);
174 if (the_file == NULL) {
175 write_protected = true;
176 the_file = open_image_file(path, false);
177 }
178 if (the_file) {
179
180 // Determine file type and fill in image_file_desc structure
181 if (!parse_image_file(the_file, desc)) {
182 fclose(the_file);
183 the_file = false;
184 return false;
185 }
186
187 // Read BAM
188 read_sector(DIR_TRACK, 0, bam);
189 bam_dirty = false;
190 return true;
191 } else
192 return false;
193 }
194
195
196 /*
197 * Open channel
198 */
199
200 uint8 ImageDrive::Open(int channel, const uint8 *name, int name_len)
201 {
202 D(bug("ImageDrive::Open channel %d, file %s\n", channel, name));
203
204 set_error(ERR_OK);
205
206 // Channel 15: execute file name as command
207 if (channel == 15) {
208 execute_cmd(name, name_len);
209 return ST_OK;
210 }
211
212 if (ch[channel].mode != CHMOD_FREE) {
213 set_error(ERR_NOCHANNEL);
214 return ST_OK;
215 }
216
217 if (name[0] == '$')
218 if (channel)
219 return open_file_ts(channel, DIR_TRACK, 0);
220 else
221 return open_directory(name + 1, name_len - 1);
222
223 if (name[0] == '#')
224 return open_direct(channel, name);
225
226 return open_file(channel, name, name_len);
227 }
228
229
230 /*
231 * Open file
232 */
233
234 uint8 ImageDrive::open_file(int channel, const uint8 *name, int name_len)
235 {
236 uint8 plain_name[NAMEBUF_LENGTH];
237 int plain_name_len;
238 int mode = FMODE_READ;
239 int type = FTYPE_DEL;
240 int rec_len = 0;
241 parse_file_name(name, name_len, plain_name, plain_name_len, mode, type, rec_len);
242 if (plain_name_len > 16)
243 plain_name_len = 16;
244
245 D(bug(" plain name %s, type %d, mode %d\n", plain_name, type, mode));
246
247 // Channel 0 is READ, channel 1 is WRITE
248 if (channel == 0 || channel == 1) {
249 mode = channel ? FMODE_WRITE : FMODE_READ;
250 if (type == FTYPE_DEL)
251 type = FTYPE_PRG;
252 }
253
254 ch[channel].writing = (mode == FMODE_WRITE || mode == FMODE_APPEND);
255
256 // Wildcards are only allowed on reading
257 if (ch[channel].writing && (strchr((const char *)plain_name, '*') || strchr((const char *)plain_name, '?'))) {
258 set_error(ERR_SYNTAX33);
259 return ST_OK;
260 }
261
262 // Check for write-protection if writing
263 if (ch[channel].writing && write_protected) {
264 set_error(ERR_WRITEPROTECT);
265 return ST_OK;
266 }
267
268 // Relative files are not supported
269 if (type == FTYPE_REL) {
270 set_error(ERR_UNIMPLEMENTED);
271 return ST_OK;
272 }
273
274 // Find file in directory
275 int dir_track, dir_sector, entry;
276 if (find_first_file(plain_name, plain_name_len, dir_track, dir_sector, entry)) {
277
278 // File exists
279 D(bug(" file exists, dir track %d, sector %d, entry %d\n", dir_track, dir_sector, entry));
280 ch[channel].dir_track = dir_track;
281 ch[channel].dir_sector = dir_sector;
282 ch[channel].entry = entry;
283 uint8 *de = dir + DIR_ENTRIES + entry * SIZEOF_DE;
284
285 // Get file type from existing file if not specified in file name
286 if (type == FTYPE_DEL)
287 type = de[DE_TYPE] & 7;
288
289 if ((de[DE_TYPE] & 7) != type) {
290
291 // File type doesn't match
292 set_error(ERR_FILETYPE);
293
294 } else if (mode == FMODE_WRITE) {
295
296 if (name[0] == '@') {
297
298 // Open old file for overwriting (save-replace)
299 return create_file(channel, plain_name, plain_name_len, type, true);
300
301 } else {
302
303 // File to be written already exists, error
304 set_error(ERR_FILEEXISTS);
305 }
306
307 } else if (mode == FMODE_APPEND) {
308
309 // Open old file for appending
310 open_file_ts(channel, de[DE_TRACK], de[DE_SECTOR]);
311
312 // Seek to end of file
313 int track = 0, sector = 0, num_blocks = 0;
314 while (ch[channel].buf[0]) {
315 if (!read_sector(track = ch[channel].buf[0], sector = ch[channel].buf[1], ch[channel].buf))
316 return ST_OK;
317 num_blocks++;
318 }
319
320 // Change channel mode to writing, adjust buffer pointer
321 ch[channel].writing = true;
322 ch[channel].buf_len = ch[channel].buf[1] + 1;
323 ch[channel].buf_ptr = ch[channel].buf + ch[channel].buf_len;
324 ch[channel].track = track;
325 ch[channel].sector = sector;
326 ch[channel].num_blocks = num_blocks;
327
328 } else if (mode == FMODE_M) {
329
330 // Open old file for reading, even if it is not closed
331 return open_file_ts(channel, de[DE_TRACK], de[DE_SECTOR]);
332
333 } else {
334
335 // Open old file for reading, error if file is open
336 if (de[DE_TYPE] & 0x80)
337 return open_file_ts(channel, de[DE_TRACK], de[DE_SECTOR]);
338 else
339 set_error(ERR_WRITEFILEOPEN);
340 }
341
342 } else {
343
344 // File doesn't exist
345 D(bug(" file not found\n"));
346
347 // Set file type to SEQ if not specified in file name
348 if (type == FTYPE_DEL)
349 type = FTYPE_SEQ;
350
351 if (mode == FMODE_WRITE) {
352
353 // Create new file for writing
354 return create_file(channel, plain_name, plain_name_len, type);
355
356 } else
357 set_error(ERR_FILENOTFOUND);
358 }
359 return ST_OK;
360 }
361
362
363 /*
364 * Open channel for reading from file given track/sector of first block
365 */
366
367 uint8 ImageDrive::open_file_ts(int channel, int track, int sector)
368 {
369 D(bug("open_file_ts track %d, sector %d\n", track, sector));
370
371 // Allocate buffer and set channel mode
372 int buf = alloc_buffer(-1);
373 if (buf == -1) {
374 set_error(ERR_NOCHANNEL);
375 return ST_OK;
376 }
377 ch[channel].buf_num = buf;
378 ch[channel].buf = ram + 0x300 + buf * 0x100;
379 ch[channel].mode = CHMOD_FILE;
380
381 // On the next call to Read, the first block will be read
382 ch[channel].buf[0] = track;
383 ch[channel].buf[1] = sector;
384 ch[channel].buf_len = 0;
385
386 return ST_OK;
387 }
388
389
390 /*
391 * Create file and open channel for writing to file
392 */
393
394 uint8 ImageDrive::create_file(int channel, const uint8 *name, int name_len, int type, bool overwrite)
395 {
396 D(bug("create_file %s, type %d\n", name, type));
397
398 // Allocate buffer
399 int buf = alloc_buffer(-1);
400 if (buf == -1) {
401 set_error(ERR_NOCHANNEL);
402 return ST_OK;
403 }
404 ch[channel].buf_num = buf;
405 ch[channel].buf = ram + 0x300 + buf * 0x100;
406
407 // Allocate new directory entry if not overwriting
408 if (!overwrite) {
409 if (!alloc_dir_entry(ch[channel].dir_track, ch[channel].dir_sector, ch[channel].entry)) {
410 free_buffer(buf);
411 return ST_OK;
412 }
413 }
414 uint8 *de = dir + DIR_ENTRIES + ch[channel].entry * SIZEOF_DE;
415
416 // Allocate first data block
417 ch[channel].track = DIR_TRACK - 1;
418 ch[channel].sector = -DATA_INTERLEAVE;
419 if (!alloc_next_block(ch[channel].track, ch[channel].sector, DATA_INTERLEAVE)) {
420 free_buffer(buf);
421 return ST_OK;
422 }
423 ch[channel].num_blocks = 1;
424 D(bug(" first data block on track %d, sector %d\n", ch[channel].track, ch[channel].sector));
425
426 // Write directory entry
427 memset(de, 0, SIZEOF_DE);
428 de[DE_TYPE] = type; // bit 7 not set -> open file
429 if (overwrite) {
430 de[DE_OVR_TRACK] = ch[channel].track;
431 de[DE_OVR_SECTOR] = ch[channel].sector;
432 } else {
433 de[DE_TRACK] = ch[channel].track;
434 de[DE_SECTOR] = ch[channel].sector;
435 }
436 memset(de + DE_NAME, 0xa0, 16);
437 memcpy(de + DE_NAME, name, name_len);
438 write_sector(ch[channel].dir_track, ch[channel].dir_sector, dir);
439
440 // Set channel descriptor
441 ch[channel].mode = CHMOD_FILE;
442 ch[channel].writing = true;
443 ch[channel].buf_ptr = ch[channel].buf + 2;
444 ch[channel].buf_len = 2;
445 return ST_OK;
446 }
447
448
449 /*
450 * Prepare directory as BASIC program (channel 0)
451 */
452
453 const char type_char_1[] = "DSPUREER";
454 const char type_char_2[] = "EERSELQG";
455 const char type_char_3[] = "LQGRL???";
456
457 uint8 ImageDrive::open_directory(const uint8 *pattern, int pattern_len)
458 {
459 // Special treatment for "$0"
460 if (pattern[0] == '0' && pattern_len == 1) {
461 pattern++;
462 pattern_len--;
463 }
464
465 // Skip everything before the ':' in the pattern
466 uint8 *t = (uint8 *)memchr(pattern, ':', pattern_len);
467 if (t) {
468 t++;
469 pattern_len -= t - pattern;
470 pattern = t;
471 }
472
473 ch[0].mode = CHMOD_DIRECTORY;
474 uint8 *p = ch[0].buf_ptr = ch[0].buf = new uint8[8192];
475
476 // Create directory title with disk name, ID and format type
477 *p++ = 0x01; // Load address $0401 (from PET days :-)
478 *p++ = 0x04;
479 *p++ = 0x01; // Dummy line link
480 *p++ = 0x01;
481 *p++ = 0; // Drive number (0) as line number
482 *p++ = 0;
483 *p++ = 0x12; // RVS ON
484 *p++ = '\"';
485
486 uint8 *q = bam + BAM_DISK_NAME;
487 for (int i=0; i<23; i++) {
488 int c;
489 if ((c = *q++) == 0xa0)
490 *p++ = ' '; // Replace 0xa0 by space
491 else
492 *p++ = c;
493 }
494 *(p-7) = '\"';
495 *p++ = 0;
496
497 // Scan all directory blocks
498 dir[DIR_NEXT_TRACK] = DIR_TRACK;
499 dir[DIR_NEXT_SECTOR] = 1;
500
501 int num_dir_blocks = 0;
502 while (dir[DIR_NEXT_TRACK] && num_dir_blocks < num_sectors[DIR_TRACK]) {
503 if (!read_sector(dir[DIR_NEXT_TRACK], dir[DIR_NEXT_SECTOR], dir))
504 return ST_OK;
505 num_dir_blocks++;
506
507 // Scan all 8 entries of a block
508 uint8 *de = dir + DIR_ENTRIES;
509 for (int j=0; j<8; j++, de+=SIZEOF_DE) {
510 if (de[DE_TYPE] && (pattern_len == 0 || match(pattern, pattern_len, de + DE_NAME))) {
511
512 // Dummy line link
513 *p++ = 0x01;
514 *p++ = 0x01;
515
516 // Line number = number of blocks
517 *p++ = de[DE_NUM_BLOCKS_L];
518 *p++ = de[DE_NUM_BLOCKS_H];
519
520 // Appropriate number of spaces to align file names
521 *p++ = ' ';
522 int n = (de[DE_NUM_BLOCKS_H] << 8) + de[DE_NUM_BLOCKS_L];
523 if (n<10) *p++ = ' ';
524 if (n<100) *p++ = ' ';
525
526 // File name enclosed in quotes
527 *p++ = '\"';
528 q = de + DE_NAME;
529 uint8 c;
530 bool m = false;
531 for (int i=0; i<16; i++) {
532 if ((c = *q++) == 0xa0) {
533 if (m)
534 *p++ = ' '; // Replace all 0xa0 by spaces
535 else
536 m = (*p++ = '\"'); // But the first by a '"'
537 } else
538 *p++ = c;
539 }
540 if (m)
541 *p++ = ' ';
542 else
543 *p++ = '\"'; // No 0xa0, then append a space
544
545 // Open files are marked by '*'
546 if (de[DE_TYPE] & 0x80)
547 *p++ = ' ';
548 else
549 *p++ = '*';
550
551 // File type
552 *p++ = type_char_1[de[DE_TYPE] & 7];
553 *p++ = type_char_2[de[DE_TYPE] & 7];
554 *p++ = type_char_3[de[DE_TYPE] & 7];
555
556 // Protected files are marked by '<'
557 if (de[DE_TYPE] & 0x40)
558 *p++ = '<';
559 else
560 *p++ = ' ';
561
562 // Appropriate number of spaces at the end
563 *p++ = ' ';
564 if (n >= 10) *p++ = ' ';
565 if (n >= 100) *p++ = ' ';
566 *p++ = 0;
567 }
568 }
569 }
570
571 // Final line, count number of free blocks
572 int n = 0;
573 for (int i=1; i<=35; i++) {
574 if (i != DIR_TRACK) // exclude track 18
575 n += num_free_blocks(i);
576 }
577
578 *p++ = 0x01; // Dummy line link
579 *p++ = 0x01;
580 *p++ = n & 0xff; // Number of free blocks as line number
581 *p++ = (n >> 8) & 0xff;
582
583 *p++ = 'B';
584 *p++ = 'L';
585 *p++ = 'O';
586 *p++ = 'C';
587 *p++ = 'K';
588 *p++ = 'S';
589 *p++ = ' ';
590 *p++ = 'F';
591 *p++ = 'R';
592 *p++ = 'E';
593 *p++ = 'E';
594 *p++ = '.';
595
596 memset(p, ' ', 13);
597 p += 13;
598
599 *p++ = 0;
600 *p++ = 0;
601 *p++ = 0;
602
603 ch[0].buf_len = p - ch[0].buf;
604 return ST_OK;
605 }
606
607
608 /*
609 * Open channel for direct buffer access
610 */
611
612 uint8 ImageDrive::open_direct(int channel, const uint8 *name)
613 {
614 int buf = -1;
615
616 if (name[1] == 0)
617 buf = alloc_buffer(-1);
618 else
619 if ((name[1] >= '0') && (name[1] <= '3') && (name[2] == 0))
620 buf = alloc_buffer(name[1] - '0');
621
622 if (buf == -1) {
623 set_error(ERR_NOCHANNEL);
624 return ST_OK;
625 }
626
627 // The buffers are in the 1541 RAM at $300 and are 256 bytes each
628 ch[channel].mode = CHMOD_DIRECT;
629 ch[channel].buf = ram + 0x300 + buf * 0x100;
630 ch[channel].buf_num = buf;
631
632 // Store actual buffer number in buffer
633 ch[channel].buf[1] = buf + '0';
634 ch[channel].buf_len = 1;
635 ch[channel].buf_ptr = ch[channel].buf + 1;
636
637 return ST_OK;
638 }
639
640
641 /*
642 * Close channel
643 */
644
645 uint8 ImageDrive::Close(int channel)
646 {
647 D(bug("ImageDrive::Close channel %d\n", channel));
648
649 switch (ch[channel].mode) {
650 case CHMOD_FREE:
651 break;
652
653 case CHMOD_COMMAND:
654 close_all_channels();
655 break;
656
657 case CHMOD_DIRECT:
658 free_buffer(ch[channel].buf_num);
659 ch[channel].buf = NULL;
660 ch[channel].mode = CHMOD_FREE;
661 break;
662
663 case CHMOD_FILE:
664 if (ch[channel].writing) {
665
666 // Current block empty? Then write CR character
667 if (ch[channel].buf_len == 2) {
668 ch[channel].buf[2] = 0x0d;
669 ch[channel].buf_len++;
670 }
671
672 // Write last data block
673 ch[channel].buf[0] = 0;
674 ch[channel].buf[1] = ch[channel].buf_len - 1;
675 D(bug(" writing last data block\n"));
676 if (!write_sector(ch[channel].track, ch[channel].sector, ch[channel].buf))
677 goto free;
678
679 // Close write file in directory
680 read_sector(ch[channel].dir_track, ch[channel].dir_sector, dir);
681 uint8 *de = dir + DIR_ENTRIES + ch[channel].entry * SIZEOF_DE;
682 de[DE_TYPE] |= 0x80;
683 de[DE_NUM_BLOCKS_L] = ch[channel].num_blocks & 0xff;
684 de[DE_NUM_BLOCKS_H] = ch[channel].num_blocks >> 8;
685 if (de[DE_OVR_TRACK]) {
686 // Overwriting, free old data blocks and set pointer to new ones
687 free_block_chain(de[DE_TRACK], de[DE_SECTOR]);
688 de[DE_TRACK] = de[DE_OVR_TRACK];
689 de[DE_SECTOR] = de[DE_OVR_SECTOR];
690 de[DE_OVR_TRACK] = de[DE_OVR_SECTOR] = 0;
691 }
692 write_sector(ch[channel].dir_track, ch[channel].dir_sector, dir);
693 D(bug(" directory entry updated\n"));
694 }
695 free: free_buffer(ch[channel].buf_num);
696 ch[channel].buf = NULL;
697 ch[channel].mode = CHMOD_FREE;
698 break;
699
700 case CHMOD_DIRECTORY:
701 delete[] ch[channel].buf;
702 ch[channel].buf = NULL;
703 ch[channel].mode = CHMOD_FREE;
704 break;
705 }
706
707 return ST_OK;
708 }
709
710
711 /*
712 * Close all channels
713 */
714
715 void ImageDrive::close_all_channels()
716 {
717 for (int i=0; i<15; i++)
718 Close(i);
719 Close(16);
720 Close(17);
721
722 cmd_len = 0;
723 }
724
725
726 /*
727 * Read from channel
728 */
729
730 uint8 ImageDrive::Read(int channel, uint8 &byte)
731 {
732 // D(bug("ImageDrive::Read channel %d\n", channel));
733
734 switch (ch[channel].mode) {
735 case CHMOD_FREE:
736 if (current_error == ERR_OK)
737 set_error(ERR_FILENOTOPEN);
738 break;
739
740 case CHMOD_COMMAND:
741 // Read error channel
742 byte = *error_ptr++;
743 if (--error_len)
744 return ST_OK;
745 else {
746 set_error(ERR_OK);
747 return ST_EOF;
748 }
749 break;
750
751 case CHMOD_FILE:
752 if (ch[channel].writing)
753 return ST_READ_TIMEOUT;
754 if (current_error != ERR_OK)
755 return ST_READ_TIMEOUT;
756
757 // Read next block if necessary
758 if (ch[channel].buf_len == 0 && ch[channel].buf[0]) {
759 D(bug(" reading next data block track %d, sector %d\n", ch[channel].buf[0], ch[channel].buf[1]));
760 if (!read_sector(ch[channel].buf[0], ch[channel].buf[1], ch[channel].buf))
761 return ST_READ_TIMEOUT;
762 ch[channel].buf_ptr = ch[channel].buf + 2;
763
764 // Determine block length
765 ch[channel].buf_len = ch[channel].buf[0] ? 254 : ch[channel].buf[1] - 1;
766 }
767
768 if (ch[channel].buf_len > 0) {
769 byte = *(ch[channel].buf_ptr)++;
770 if (--(ch[channel].buf_len) == 0 && ch[channel].buf[0] == 0)
771 return ST_EOF;
772 else
773 return ST_OK;
774 } else
775 return ST_READ_TIMEOUT;
776 break;
777
778 case CHMOD_DIRECTORY:
779 case CHMOD_DIRECT:
780 if (ch[channel].buf_len > 0) {
781 byte = *(ch[channel].buf_ptr)++;
782 if (--(ch[channel].buf_len))
783 return ST_OK;
784 else
785 return ST_EOF;
786 } else
787 return ST_READ_TIMEOUT;
788 break;
789 }
790 return ST_READ_TIMEOUT;
791 }
792
793
794 /*
795 * Write byte to channel
796 */
797
798 uint8 ImageDrive::Write(int channel, uint8 byte, bool eoi)
799 {
800 // D(bug("ImageDrive::Write channel %d, byte %02x, eoi %d\n", channel, byte, eoi));
801
802 switch (ch[channel].mode) {
803 case CHMOD_FREE:
804 if (current_error == ERR_OK)
805 set_error(ERR_FILENOTOPEN);
806 break;
807
808 case CHMOD_COMMAND:
809 // Collect characters and execute command on EOI
810 if (cmd_len > 58) {
811 set_error(ERR_SYNTAX32);
812 return ST_TIMEOUT;
813 }
814
815 cmd_buf[cmd_len++] = byte;
816
817 if (eoi) {
818 execute_cmd(cmd_buf, cmd_len);
819 cmd_len = 0;
820 }
821 return ST_OK;
822
823 case CHMOD_DIRECTORY:
824 set_error(ERR_WRITEFILEOPEN);
825 break;
826
827 case CHMOD_FILE:
828 if (!ch[channel].writing)
829 return ST_TIMEOUT;
830 if (current_error != ERR_OK)
831 return ST_TIMEOUT;
832
833 // Buffer full?
834 if (ch[channel].buf_len >= 256) {
835
836 // Yes, allocate new block
837 int track = ch[channel].track, sector = ch[channel].sector;
838 if (!alloc_next_block(track, sector, DATA_INTERLEAVE))
839 return ST_TIMEOUT;
840 ch[channel].num_blocks++;
841 D(bug("next data block on track %d, sector %d\n", track, sector));
842
843 // Write buffer with link to new block
844 ch[channel].buf[0] = track;
845 ch[channel].buf[1] = sector;
846 write_sector(ch[channel].track, ch[channel].sector, ch[channel].buf);
847
848 // Reset buffer
849 ch[channel].buf_ptr = ch[channel].buf + 2;
850 ch[channel].buf_len = 2;
851 ch[channel].track = track;
852 ch[channel].sector = sector;
853 }
854 *(ch[channel].buf_ptr)++ = byte;
855 ch[channel].buf_len++;
856 return ST_OK;
857
858 case CHMOD_DIRECT:
859 if (ch[channel].buf_len < 256) {
860 *(ch[channel].buf_ptr)++ = byte;
861 ch[channel].buf_len++;
862 return ST_OK;
863 } else
864 return ST_TIMEOUT;
865 break;
866 }
867 return ST_TIMEOUT;
868 }
869
870
871 /*
872 * Reset drive
873 */
874
875 void ImageDrive::Reset(void)
876 {
877 close_all_channels();
878
879 cmd_len = 0;
880 for (int i=0; i<4; i++)
881 buf_free[i] = true;
882
883 if (bam_dirty) {
884 write_sector(DIR_TRACK, 0, bam);
885 bam_dirty = false;
886 }
887
888 memset(ram, 0, sizeof(ram));
889
890 read_sector(DIR_TRACK, 0, bam);
891
892 set_error(ERR_STARTUP);
893 }
894
895
896 /*
897 * Allocate floppy buffer
898 * -> Desired buffer number or -1
899 * <- Allocated buffer number or -1
900 */
901
902 int ImageDrive::alloc_buffer(int want)
903 {
904 if (want == -1) {
905 for (want=3; want>=0; want--)
906 if (buf_free[want]) {
907 buf_free[want] = false;
908 return want;
909 }
910 return -1;
911 }
912
913 if (want < 4)
914 if (buf_free[want]) {
915 buf_free[want] = false;
916 return want;
917 } else
918 return -1;
919 else
920 return -1;
921 }
922
923
924 /*
925 * Free floppy buffer
926 */
927
928 void ImageDrive::free_buffer(int buf)
929 {
930 buf_free[buf] = true;
931 }
932
933
934 /*
935 * Search file in directory, return directory track/sector and entry number
936 * false: not found, true: found
937 */
938
939 // Return true if name 'n' matches pattern 'p'
940 static bool match(const uint8 *p, int p_len, const uint8 *n)
941 {
942 if (p_len > 16)
943 p_len = 16;
944
945 int c = 0;
946 while (p_len-- > 0) {
947 if (*p == '*') // Wildcard '*' matches all following characters
948 return true;
949 if ((*p != *n) && (*p != '?')) // Wildcard '?' matches single character
950 return false;
951 p++; n++; c++;
952 }
953
954 return *n == 0xa0 || c == 16;
955 }
956
957 bool ImageDrive::find_file(const uint8 *pattern, int pattern_len, int &dir_track, int &dir_sector, int &entry, bool cont)
958 {
959 // Counter to prevent cyclic directories from resulting in an infinite loop
960 int num_dir_blocks = 0;
961
962 // Pointer to current directory entry
963 uint8 *de = NULL;
964 if (cont)
965 de = dir + DIR_ENTRIES + entry * SIZEOF_DE;
966 else {
967 dir[DIR_NEXT_TRACK] = DIR_TRACK;
968 dir[DIR_NEXT_SECTOR] = 1;
969 entry = 8;
970 }
971
972 while (num_dir_blocks < num_sectors[DIR_TRACK]) {
973
974 // Goto next entry
975 entry++; de += SIZEOF_DE;
976 if (entry >= 8) {
977
978 // Read next directory block
979 if (dir[DIR_NEXT_TRACK] == 0)
980 return false;
981 if (!read_sector(dir_track = dir[DIR_NEXT_TRACK], dir_sector = dir[DIR_NEXT_SECTOR], dir))
982 return false;
983 num_dir_blocks++;
984 entry = 0;
985 de = dir + DIR_ENTRIES;
986 }
987
988 // Does entry match pattern?
989 if (de[DE_TYPE] && match(pattern, pattern_len, de + DE_NAME))
990 return true;
991 }
992 return false;
993 }
994
995 bool ImageDrive::find_first_file(const uint8 *pattern, int pattern_len, int &dir_track, int &dir_sector, int &entry)
996 {
997 return find_file(pattern, pattern_len, dir_track, dir_sector, entry, false);
998 }
999
1000 bool ImageDrive::find_next_file(const uint8 *pattern, int pattern_len, int &dir_track, int &dir_sector, int &entry)
1001 {
1002 return find_file(pattern, pattern_len, dir_track, dir_sector, entry, true);
1003 }
1004
1005
1006 /*
1007 * Allocate new entry in directory, returns false on error (usually when
1008 * all sectors of track 18 are allocated)
1009 * The track/sector and entry numbers are returned
1010 */
1011
1012 bool ImageDrive::alloc_dir_entry(int &track, int &sector, int &entry)
1013 {
1014 // First look for free entry in existing directory blocks
1015 dir[DIR_NEXT_TRACK] = DIR_TRACK;
1016 dir[DIR_NEXT_SECTOR] = 1;
1017 while (dir[DIR_NEXT_TRACK]) {
1018 if (!read_sector(track = dir[DIR_NEXT_TRACK], sector = dir[DIR_NEXT_SECTOR], dir))
1019 return false;
1020
1021 uint8 *de = dir + DIR_ENTRIES;
1022 for (entry=0; entry<8; entry++, de+=SIZEOF_DE) {
1023 if (de[DE_TYPE] == 0) {
1024 D(bug(" allocated entry %d in dir track %d, sector %d\n", entry, track, sector));
1025 return true;
1026 }
1027 }
1028 }
1029
1030 // No free entry found, allocate new directory block
1031 int last_track = track, last_sector = sector;
1032 if (!alloc_next_block(track, sector, DIR_INTERLEAVE))
1033 return false;
1034 D(bug(" new directory block track %d, sector %d\n", track, sector));
1035
1036 // Write link to new block to last block
1037 dir[DIR_NEXT_TRACK] = track;
1038 dir[DIR_NEXT_SECTOR] = sector;
1039 write_sector(last_track, last_sector, dir);
1040
1041 // Write new empty directory block and return first entry
1042 memset(dir, 0, 256);
1043 dir[DIR_NEXT_SECTOR] = 0xff;
1044 write_sector(track, sector, dir);
1045 entry = 0;
1046 return true;
1047 }
1048
1049 /*
1050 * Test if block is free in BAM (track/sector are not checked for validity)
1051 */
1052
1053 bool ImageDrive::is_block_free(int track, int sector)
1054 {
1055 uint8 *p = bam + BAM_BITMAP + (track - 1) * 4;
1056 int byte = sector / 8 + 1;
1057 int bit = sector & 7;
1058 return p[byte] & (1 << bit);
1059 }
1060
1061
1062 /*
1063 * Get number of free blocks on a track
1064 */
1065
1066 int ImageDrive::num_free_blocks(int track)
1067 {
1068 return bam[BAM_BITMAP + (track - 1) * 4];
1069 }
1070
1071
1072 /*
1073 * Clear BAM, mark all blocks as free
1074 */
1075
1076 static void clear_bam(uint8 *bam)
1077 {
1078 for (int track=1; track<=35; track++) {
1079 static const uint8 num2bits[8] = {0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
1080 (bam + BAM_BITMAP)[(track-1) * 4 + 0] = num_sectors[track];
1081 (bam + BAM_BITMAP)[(track-1) * 4 + 1] = 0xff;
1082 (bam + BAM_BITMAP)[(track-1) * 4 + 2] = 0xff;
1083 (bam + BAM_BITMAP)[(track-1) * 4 + 3] = num2bits[num_sectors[track] - 16];
1084 }
1085 }
1086
1087
1088 /*
1089 * Allocate block in BAM, returns error code
1090 */
1091
1092 int ImageDrive::alloc_block(int track, int sector)
1093 {
1094 if (track < 1 || track > 35 || sector < 0 || sector >= num_sectors[track])
1095 return ERR_ILLEGALTS;
1096
1097 uint8 *p = bam + BAM_BITMAP + (track - 1) * 4;
1098 int byte = sector / 8 + 1;
1099 int bit = sector & 7;
1100
1101 // Block free?
1102 if (p[byte] & (1 << bit)) {
1103
1104 // Yes, allocate and decrement free block count
1105 D(bug("allocating block at track %d, sector %d\n", track, sector));
1106 p[byte] &= ~(1 << bit);
1107 p[0]--;
1108 bam_dirty = true;
1109 return ERR_OK;
1110
1111 } else
1112 return ERR_NOBLOCK;
1113 }
1114
1115
1116 /*
1117 * Free block in BAM, returns error code
1118 */
1119
1120 int ImageDrive::free_block(int track, int sector)
1121 {
1122 if (track < 1 || track > 35 || sector < 0 || sector >= num_sectors[track])
1123 return ERR_ILLEGALTS;
1124
1125 uint8 *p = bam + BAM_BITMAP + (track - 1) * 4;
1126 int byte = sector / 8 + 1;
1127 int bit = sector & 7;
1128
1129 // Block allocated?
1130 if (!(p[byte] & (1 << bit))) {
1131
1132 // Yes, free and increment free block count
1133 D(bug("freeing block at track %d, sector %d\n", track, sector));
1134 p[byte] |= (1 << bit);
1135 p[0]++;
1136 bam_dirty = true;
1137 }
1138 return ERR_OK;
1139 }
1140
1141
1142 /*
1143 * Allocate chain of data blocks in BAM
1144 */
1145
1146 bool ImageDrive::alloc_block_chain(int track, int sector)
1147 {
1148 uint8 buf[256];
1149 while (alloc_block(track, sector) == ERR_OK) {
1150 if (!read_sector(track, sector, buf))
1151 return false;
1152 track = buf[0];
1153 sector = buf[1];
1154 }
1155 return true;
1156 }
1157
1158
1159 /*
1160 * Free chain of data blocks in BAM
1161 */
1162
1163 bool ImageDrive::free_block_chain(int track, int sector)
1164 {
1165 uint8 buf[256];
1166 while (free_block(track, sector) == ERR_OK) {
1167 if (!read_sector(track, sector, buf))
1168 return false;
1169 track = buf[0];
1170 sector = buf[1];
1171 }
1172 return true;
1173 }
1174
1175
1176 /*
1177 * Search and allocate next free block, returns false if no more blocks
1178 * are free (ERR_DISKFULL is also set in this case)
1179 * "track" and "sector" must be set to the block where the search should
1180 * begin
1181 */
1182
1183 bool ImageDrive::alloc_next_block(int &track, int &sector, int interleave)
1184 {
1185 // Find track with free blocks
1186 bool side_changed = false;
1187 while (num_free_blocks(track) == 0) {
1188 if (track == DIR_TRACK) { // Directory doesn't grow to other tracks
1189 full: track = sector = 0;
1190 set_error(ERR_DISKFULL);
1191 return false;
1192 } else if (track > DIR_TRACK) {
1193 track++;
1194 if (track > 35) {
1195 if (!side_changed)
1196 side_changed = true;
1197 else
1198 goto full;
1199 track = DIR_TRACK - 1;
1200 sector = 0;
1201 }
1202 } else {
1203 track--;
1204 if (track < 1) {
1205 if (!side_changed)
1206 side_changed = true;
1207 else
1208 goto full;
1209 track = DIR_TRACK + 1;
1210 sector = 0;
1211 }
1212 }
1213 }
1214
1215 // Find next free block on track
1216 int num = num_sectors[track];
1217 sector = sector + interleave;
1218 if (sector >= num) {
1219 sector -= num;
1220 if (sector)
1221 sector--;
1222 }
1223 while (!is_block_free(track, sector)) {
1224 sector++;
1225 if (sector >= num_sectors[track]) {
1226 sector = 0;
1227 while (!is_block_free(track, sector)) {
1228 sector++;
1229 if (sector >= num_sectors[track]) {
1230 // Something is wrong: the BAM free block count for this
1231 // track was >0, but we found no free blocks
1232 track = sector = 0;
1233 set_error(ERR_DIRERROR);
1234 return false;
1235 }
1236 }
1237 }
1238 }
1239
1240 alloc_block(track, sector);
1241 return true;
1242 }
1243
1244
1245 /*
1246 * Sector reading/writing routines
1247 */
1248
1249 static long offset_from_ts(const image_file_desc &desc, int track, int sector)
1250 {
1251 if ((track < 1) || (track > desc.num_tracks)
1252 || (sector < 0) || (sector >= num_sectors[track]))
1253 return -1;
1254
1255 return ((accum_num_sectors[track] + sector) << 8) + desc.header_size;
1256 }
1257
1258 // Get number of sectors per given track
1259 int sectors_per_track(const image_file_desc &desc, int track)
1260 {
1261 return num_sectors[track];
1262 }
1263
1264 // Get reference to error info byte of given track/sector
1265 uint8 &error_info_for_sector(image_file_desc &desc, int track, int sector)
1266 {
1267 return desc.error_info[accum_num_sectors[track] + sector];
1268 }
1269
1270 static inline const uint8 &error_info_for_sector(const image_file_desc &desc, int track, int sector)
1271 {
1272 return desc.error_info[accum_num_sectors[track] + sector];
1273 }
1274
1275 const int conv_job_error[16] = {
1276 ERR_OK, // 0 -> 00 OK
1277 ERR_OK, // 1 -> 00 OK
1278 ERR_READ20, // 2 -> 20 READ ERROR
1279 ERR_READ21, // 3 -> 21 READ ERROR
1280 ERR_READ22, // 4 -> 22 READ ERROR
1281 ERR_READ23, // 5 -> 23 READ ERROR
1282 ERR_READ24, // 6 -> 24 READ ERROR (undetected by 1541)
1283 ERR_WRITE25, // 7 -> 25 WRITE ERROR
1284 ERR_WRITEPROTECT, // 8 -> 26 WRITE PROTECT ON
1285 ERR_READ27, // 9 -> 27 READ ERROR
1286 ERR_WRITE28, // 10 -> 28 WRITE ERROR
1287 ERR_DISKID, // 11 -> 29 DISK ID MISMATCH
1288 ERR_OK, // 12 -> 00 OK
1289 ERR_OK, // 13 -> 00 OK
1290 ERR_OK, // 14 -> 00 OK
1291 ERR_NOTREADY // 15 -> 74 DRIVE NOT READY
1292 };
1293
1294 // Read sector, return error code
1295 int read_sector(FILE *f, const image_file_desc &desc, int track, int sector, uint8 *buffer)
1296 {
1297 // Convert track/sector to byte offset in file
1298 long offset = offset_from_ts(desc, track, sector);
1299 if (offset < 0)
1300 return ERR_ILLEGALTS;
1301
1302 if (f == NULL)
1303 return ERR_NOTREADY;
1304
1305 fseek(f, offset, SEEK_SET);
1306 if (fread(buffer, 1, 256, f) != 256)
1307 return ERR_READ22;
1308 else {
1309 unsigned int error = error_info_for_sector(desc, track, sector);
1310 return conv_job_error[error & 0x0f];
1311 }
1312 }
1313
1314 // Write sector, return error code
1315 int write_sector(FILE *f, const image_file_desc &desc, int track, int sector, uint8 *buffer)
1316 {
1317 // Convert track/sector to byte offset in file
1318 long offset = offset_from_ts(desc, track, sector);
1319 if (offset < 0)
1320 return ERR_ILLEGALTS;
1321
1322 if (f == NULL)
1323 return ERR_NOTREADY;
1324
1325 fseek(f, offset, SEEK_SET);
1326 if (fwrite(buffer, 1, 256, f) != 256)
1327 return ERR_WRITE25;
1328 else
1329 return ERR_OK;
1330 }
1331
1332 // Read sector and set error message, returns false on error
1333 bool ImageDrive::read_sector(int track, int sector, uint8 *buffer)
1334 {
1335 int error = ::read_sector(the_file, desc, track, sector, buffer);
1336 if (error)
1337 set_error(error, track, sector);
1338 return error == ERR_OK;
1339 }
1340
1341 // Write sector and set error message, returns false on error
1342 bool ImageDrive::write_sector(int track, int sector, uint8 *buffer)
1343 {
1344 int error = ::write_sector(the_file, desc, track, sector, buffer);
1345 if (error)
1346 set_error(error, track, sector);
1347 return error == ERR_OK;
1348 }
1349
1350 // Write error info back to image file
1351 void write_back_error_info(FILE *f, const image_file_desc &desc)
1352 {
1353 if (desc.type == TYPE_D64 && desc.has_error_info) {
1354 int num_sectors = desc.num_tracks == 40 ? NUM_SECTORS_40 : NUM_SECTORS_35;
1355 fseek(f, num_sectors * 256, SEEK_SET);
1356 fwrite(desc.error_info, num_sectors, 1, f);
1357 }
1358 }
1359
1360 // Format disk image
1361 bool format_image(FILE *f, image_file_desc &desc, bool lowlevel, uint8 id1, uint8 id2, const uint8 *disk_name, int disk_name_len)
1362 {
1363 uint8 p[256];
1364
1365 if (lowlevel) {
1366
1367 // Fill buffer with 1541 empty sector pattern (4b 01 01 ...,
1368 // except on track 1 where it's 01 01 01 ...)
1369 memset(p, 1, 256);
1370
1371 // Overwrite all blocks
1372 for (int track=1; track<=35; track++) {
1373 if (track == 2)
1374 p[0] = 0x4b;
1375 for (int sector=0; sector<num_sectors[track]; sector++) {
1376 if (write_sector(f, desc, track, sector, p) != ERR_OK)
1377 return false;
1378 }
1379 }
1380
1381 // Clear and write error info
1382 memset(desc.error_info, 1, sizeof(desc.error_info));
1383 write_back_error_info(f, desc);
1384
1385 // Clear BAM
1386 memset(p, 0, 256);
1387
1388 } else {
1389
1390 // Read BAM
1391 if (read_sector(f, desc, DIR_TRACK, 0, p) != ERR_OK)
1392 return false;
1393 }
1394
1395 // Create and write empty BAM
1396 p[BAM_DIR_TRACK] = DIR_TRACK;
1397 p[BAM_DIR_SECTOR] = 1;
1398 p[BAM_FMT_TYPE] = 'A';
1399 clear_bam(p);
1400 p[BAM_BITMAP + (DIR_TRACK - 1) * 4 + 0] -= 2; // Allocate BAM and first directory block
1401 p[BAM_BITMAP + (DIR_TRACK - 1) * 4 + 1] &= 0xfc;
1402 memset(p + BAM_DISK_NAME, 0xa0, 27);
1403 if (disk_name_len > 16)
1404 disk_name_len = 16;
1405 memcpy(p + BAM_DISK_NAME, disk_name, disk_name_len);
1406 p[BAM_DISK_ID] = id1;
1407 p[BAM_DISK_ID + 1] = id2;
1408 p[BAM_FMT_CHAR] = '2';
1409 p[BAM_FMT_CHAR + 1] = 'A';
1410 if (write_sector(f, desc, DIR_TRACK, 0, p) != ERR_OK)
1411 return false;
1412
1413 // Create and write empty directory
1414 memset(p, 0, 256);
1415 p[1] = 255;
1416 return write_sector(f, desc, DIR_TRACK, 1, p) == ERR_OK;
1417 }
1418
1419
1420 /*
1421 * Execute drive commands
1422 */
1423
1424 // BLOCK-READ:channel,0,track,sector
1425 void ImageDrive::block_read_cmd(int channel, int track, int sector, bool user_cmd)
1426 {
1427 if (channel >= 16 || ch[channel].mode != CHMOD_DIRECT) {
1428 set_error(ERR_NOCHANNEL);
1429 return;
1430 }
1431 if (!read_sector(track, sector, ch[channel].buf))
1432 return;
1433 if (user_cmd) {
1434 ch[channel].buf_len = 256;
1435 ch[channel].buf_ptr = ch[channel].buf;
1436 } else {
1437 ch[channel].buf_len = ch[channel].buf[0];
1438 ch[channel].buf_ptr = ch[channel].buf + 1;
1439 }
1440 }
1441
1442 // BLOCK-WRITE:channel,0,track,sector
1443 void ImageDrive::block_write_cmd(int channel, int track, int sector, bool user_cmd)
1444 {
1445 if (write_protected) {
1446 set_error(ERR_WRITEPROTECT);
1447 return;
1448 }
1449 if (channel >= 16 || ch[channel].mode != CHMOD_DIRECT) {
1450 set_error(ERR_NOCHANNEL);
1451 return;
1452 }
1453 if (!user_cmd)
1454 ch[channel].buf[0] = ch[channel].buf_len ? ch[channel].buf_len - 1 : 1;
1455 if (!write_sector(track, sector, ch[channel].buf))
1456 return;
1457 if (!user_cmd) {
1458 ch[channel].buf_len = 1;
1459 ch[channel].buf_ptr = ch[channel].buf + 1;
1460 }
1461 }
1462
1463 // BLOCK-ALLOCATE:0,track,sector
1464 void ImageDrive::block_allocate_cmd(int track, int sector)
1465 {
1466 int err = alloc_block(track, sector);
1467 if (err) {
1468 if (err == ERR_NOBLOCK) {
1469 // Find next free block and return its track/sector address in the
1470 // error message (only look on higher tracks)
1471 for (;;) {
1472 sector++;
1473 if (sector >= num_sectors[track]) {
1474 track++;
1475 sector = 0;
1476 if (track > 35) {
1477 set_error(ERR_NOBLOCK, 0, 0);
1478 return;
1479 }
1480 }
1481 if (is_block_free(track, sector)) {
1482 set_error(ERR_NOBLOCK, track, sector);
1483 return;
1484 }
1485 }
1486 } else
1487 set_error(err, track, sector);
1488 }
1489 }
1490
1491 // BLOCK-FREE:0,track,sector
1492 void ImageDrive::block_free_cmd(int track, int sector)
1493 {
1494 int err = free_block(track, sector);
1495 if (err)
1496 set_error(err, track, sector);
1497 }
1498
1499 // BUFFER-POINTER:channel,pos
1500 void ImageDrive::buffer_pointer_cmd(int channel, int pos)
1501 {
1502 if (channel >= 16 || ch[channel].mode != CHMOD_DIRECT) {
1503 set_error(ERR_NOCHANNEL);
1504 return;
1505 }
1506 ch[channel].buf_ptr = ch[channel].buf + pos;
1507 ch[channel].buf_len = 256 - pos;
1508 }
1509
1510 // M-R<adr low><adr high>[<number>]
1511 void ImageDrive::mem_read_cmd(uint16 adr, uint8 len)
1512 {
1513 error_len = len;
1514 if (adr >= 0x300 && adr < 0x1000) {
1515 // Read from RAM
1516 error_ptr = (char *)ram + (adr & 0x7ff);
1517 } else if (adr >= 0xc000) {
1518 // Read from ROM
1519 error_ptr = (char *)(TheC64->ROM1541) + (adr - 0xc000);
1520 } else {
1521 unsupp_cmd();
1522 memset(error_buf, 0, len);
1523 error_ptr = error_buf;
1524 }
1525 }
1526
1527 // M-W<adr low><adr high><number><data...>
1528 void ImageDrive::mem_write_cmd(uint16 adr, uint8 len, uint8 *p)
1529 {
1530 while (len) {
1531 if (adr >= 0x300 && adr < 0x1000) {
1532 // Write to RAM
1533 ram[adr & 0x7ff] = *p;
1534 } else if (adr < 0xc000) {
1535 unsupp_cmd();
1536 return;
1537 }
1538 len--; adr++; p++;
1539 }
1540 }
1541
1542 // COPY:new=file1,file2,...
1543 // ^ ^
1544 // new_file old_files
1545 void ImageDrive::copy_cmd(const uint8 *new_file, int new_file_len, const uint8 *old_files, int old_files_len)
1546 {
1547 // Check if destination file is already present
1548 int dir_track, dir_sector, entry;
1549 if (find_first_file(new_file, new_file_len, dir_track, dir_sector, entry)) {
1550 set_error(ERR_FILEEXISTS);
1551 return;
1552 }
1553
1554 // Loop for all source files
1555 bool first = true;
1556 while (old_files_len > 0) {
1557 uint8 *comma = (uint8 *)memchr(old_files, ',', old_files_len);
1558 int name_len = comma ? comma - old_files : old_files_len;
1559
1560 // Check if source file is present
1561 if (!find_first_file(old_files, name_len, dir_track, dir_sector, entry)) {
1562 set_error(ERR_FILENOTFOUND);
1563 Close(17);
1564 return;
1565 }
1566 uint8 *de = dir + DIR_ENTRIES + entry * SIZEOF_DE;
1567 uint8 type = de[DE_TYPE] & 7, track = de[DE_TRACK], sector = de[DE_SECTOR];
1568
1569 // If this is the first source file, open internal write channel for destination file
1570 if (first) {
1571 create_file(17, new_file, new_file_len, type, false);
1572 if (ch[17].mode == CHMOD_FREE)
1573 return;
1574 first = false;
1575 }
1576
1577 // Open internal read channel for source file
1578 open_file_ts(16, track, sector);
1579 if (ch[16].mode == CHMOD_FREE) {
1580 Close(17);
1581 return;
1582 }
1583
1584 // Copy file
1585 uint8 byte, st;
1586 do {
1587 st = Read(16, byte);
1588 Write(17, byte, false);
1589 } while (st == ST_OK);
1590 Close(16);
1591 if (st != ST_EOF) {
1592 Close(17);
1593 return;
1594 }
1595
1596 if (comma) {
1597 old_files_len -= name_len + 1;
1598 old_files = comma + 1;
1599 } else
1600 old_files_len = 0;
1601 }
1602 Close(17);
1603 }
1604
1605 // RENAME:new=old
1606 // ^ ^
1607 // new_file old_file
1608 void ImageDrive::rename_cmd(const uint8 *new_file, int new_file_len, const uint8 *old_file, int old_file_len)
1609 {
1610 // Check if destination file is already present
1611 int dir_track, dir_sector, entry;
1612 if (find_first_file(new_file, new_file_len, dir_track, dir_sector, entry)) {
1613 set_error(ERR_FILEEXISTS);
1614 return;
1615 }
1616
1617 // Check if source file is present
1618 if (!find_first_file(old_file, old_file_len, dir_track, dir_sector, entry)) {
1619 set_error(ERR_FILENOTFOUND);
1620 return;
1621 }
1622
1623 // Check for write-protection
1624 if (write_protected) {
1625 set_error(ERR_WRITEPROTECT);
1626 return;
1627 }
1628
1629 // Rename file in directory entry
1630 uint8 *p = dir + DIR_ENTRIES + entry * SIZEOF_DE;
1631 memset(p + DE_NAME, 0xa0, 16);
1632 memcpy(p + DE_NAME, new_file, new_file_len);
1633 write_sector(dir_track, dir_sector, dir);
1634 }
1635
1636 // SCRATCH:file1,file2,...
1637 // ^
1638 // files
1639 void ImageDrive::scratch_cmd(const uint8 *files, int files_len)
1640 {
1641 // Check for write-protection
1642 if (write_protected) {
1643 set_error(ERR_WRITEPROTECT);
1644 return;
1645 }
1646
1647 // Loop for all files
1648 int num_files = 0;
1649 while (files_len > 0) {
1650 uint8 *comma = (uint8 *)memchr(files, ',', files_len);
1651 int name_len = comma ? comma - files : files_len;
1652
1653 int dir_track, dir_sector, entry;
1654 if (find_first_file(files, name_len, dir_track, dir_sector, entry)) {
1655 do {
1656 uint8 *de = dir + DIR_ENTRIES + entry * SIZEOF_DE;
1657
1658 // File protected? Then skip
1659 if (de[DE_TYPE] & 0x40)
1660 continue;
1661
1662 // Free allocated data blocks and side sectors
1663 free_block_chain(de[DE_TRACK], de[DE_SECTOR]);
1664 free_block_chain(de[DE_SIDE_TRACK], de[DE_SIDE_SECTOR]);
1665
1666 // Clear file type
1667 de[DE_TYPE] = 0;
1668
1669 // Write directory block back
1670 write_sector(dir_track, dir_sector, dir);
1671 num_files++;
1672 } while (find_next_file(files, name_len, dir_track, dir_sector, entry));
1673 }
1674
1675 if (comma) {
1676 files_len -= name_len + 1;
1677 files = comma + 1;
1678 } else
1679 files_len = 0;
1680 }
1681
1682 // Report number of files scratched
1683 set_error(ERR_SCRATCHED, num_files);
1684 }
1685
1686 // INITIALIZE
1687 void ImageDrive::initialize_cmd(void)
1688 {
1689 // Close all channels and re-read BAM
1690 close_all_channels();
1691 if (bam_dirty) {
1692 write_sector(DIR_TRACK, 0, bam);
1693 bam_dirty = false;
1694 }
1695 read_sector(DIR_TRACK, 0, bam);
1696 }
1697
1698 // NEW:name,id
1699 // ^ ^
1700 // name comma (or NULL)
1701 void ImageDrive::new_cmd(const uint8 *name, int name_len, const uint8 *comma)
1702 {
1703 // Check for write-protection
1704 if (write_protected) {
1705 set_error(ERR_WRITEPROTECT);
1706 return;
1707 }
1708
1709 // Remember current ID
1710 uint8 id1 = bam[BAM_DISK_ID], id2 = bam[BAM_DISK_ID + 1];
1711
1712 // Formatting with ID?
1713 if (comma) {
1714
1715 close_all_channels();
1716
1717 // Clear BAM buffer
1718 memset(bam, 0, 256);
1719
1720 // Get ID from command
1721 if (comma[1]) {
1722 id1 = comma[1];
1723 id2 = comma[2] ? comma[2] : ' ';
1724 } else {
1725 id1 = id2 = ' ';
1726 }
1727 }
1728
1729 // Format disk image
1730 format_image(the_file, desc, comma, id1, id2, name, name_len);
1731
1732 // Re-read BAM
1733 read_sector(DIR_TRACK, 0, bam);
1734 bam_dirty = false;
1735 }
1736
1737 // VALIDATE
1738 void ImageDrive::validate_cmd(void)
1739 {
1740 // Backup of old BAM in case something goes amiss
1741 uint8 old_bam[256];
1742 memcpy(old_bam, bam, 256);
1743
1744 // Clear BAM
1745 clear_bam(bam);
1746 bam_dirty = true;
1747
1748 // Allocate BAM and directory
1749 if (!alloc_block_chain(DIR_TRACK, 0)) {
1750 memcpy(bam, old_bam, 256);
1751 return;
1752 }
1753
1754 // Allocate all file data and side sector blocks
1755 int dir_track, dir_sector, entry;
1756 if (find_first_file((uint8 *)"*", 1, dir_track, dir_sector, entry)) {
1757 do {
1758 uint8 *de = dir + DIR_ENTRIES + entry * SIZEOF_DE;
1759
1760 if (de[DE_TYPE] & 0x80) {
1761 // Closed file, allocate all file data and side sector blocks
1762 if (!alloc_block_chain(de[DE_TRACK], de[DE_SECTOR]) || !alloc_block_chain(de[DE_SIDE_TRACK], de[DE_SIDE_SECTOR])) {
1763 memcpy(bam, old_bam, 256);
1764 return;
1765 }
1766 } else {
1767 // Open file, delete it
1768 de[DE_TYPE] = 0;
1769 write_sector(dir_track, dir_sector, dir);
1770 }
1771 } while (find_next_file((uint8 *)"*", 1, dir_track, dir_sector, entry));
1772 }
1773 }
1774
1775
1776 /*
1777 * Check whether file with given header (64 bytes) and size looks like one
1778 * of the file types supported by this module
1779 */
1780
1781 static bool is_d64_file(const uint8 *header, long size)
1782 {
1783 return size == NUM_SECTORS_35 * 256 || size == NUM_SECTORS_35 * 257
1784 || size == NUM_SECTORS_40 * 256 || size == NUM_SECTORS_40 * 257;
1785 }
1786
1787 static bool is_ed64_file(const uint8 *header, long size)
1788 {
1789 // 35-track d64 file with header ID at the end (only used internally for
1790 // converted zipcode files)
1791 return size == NUM_SECTORS_35 * 256 + 2;
1792 }
1793
1794 static bool is_x64_file(const uint8 *header, long size)
1795 {
1796 return memcmp(header, "C\x15\x41\x64\x01\x02", 6) == 0;
1797 }
1798
1799 static bool is_zipcode_file(const char *path)
1800 {
1801 #if 0
1802 string base, part;
1803 SplitPath(path, base, part);
1804 return part.length() > 2 && part[0] >= '1' && part[0] <= '4' && part[1] == '!';
1805 #else
1806 return false;
1807 #endif
1808 }
1809
1810 bool IsImageFile(const char *path, const uint8 *header, long size)
1811 {
1812 return is_d64_file(header, size) || is_x64_file(header, size) || is_zipcode_file(path);
1813 }
1814
1815
1816 #if 0
1817 /*
1818 * Convert zipcode file to extended d64 file (d64 file with header ID)
1819 */
1820
1821 static FILE *open_zipcode_file(FILE *old, int num, const string &base, string &part, uint8 &id1, uint8 &id2)
1822 {
1823 if (old)
1824 fclose(old);
1825 part[0] = num + '1';
1826 FILE *f = fopen(AddToPath(base, part).c_str(), "rb");
1827 if (f == NULL)
1828 return NULL;
1829 if (fseek(f, 2, SEEK_SET) < 0) {
1830 fclose(f);
1831 return NULL;
1832 }
1833 if (num == 0) {
1834 id1 = getc(f);
1835 id2 = getc(f);
1836 }
1837 return f;
1838 }
1839
1840 static FILE *convert_zipcode_to_ed64(const string &path)
1841 {
1842 FILE *in = NULL, *out = NULL;
1843 uint8 id1, id2;
1844
1845 // Split input file name
1846 string base, part;
1847 SplitPath(path, base, part);
1848
1849 // Open output file
1850 out = tmpfile();
1851 if (out == NULL)
1852 goto error;
1853
1854 // Decode all tracks
1855 for (int track=1; track<=35; track++) {
1856 int max_sect = 17 + ((track < 31) ? 1 : 0) + ((track < 25) ? 1 : 0) + ((track < 18) ? 2 : 0);
1857
1858 // Select appropriate input file
1859 switch (track) {
1860 case 1:
1861 if ((in = open_zipcode_file(NULL, 0, base, part, id1, id2)) == NULL)
1862 goto error;
1863 break;
1864 case 9:
1865 if ((in = open_zipcode_file(in, 1, base, part, id1, id2)) == NULL)
1866 goto error;
1867 break;
1868 case 17:
1869 if ((in = open_zipcode_file(in, 2, base, part, id1, id2)) == NULL)
1870 goto error;
1871 break;
1872 case 26:
1873 if ((in = open_zipcode_file(in, 3, base, part, id1, id2)) == NULL)
1874 goto error;
1875 break;
1876 }
1877
1878 // Clear "sector read" flags
1879 bool sect_flag[21];
1880 for (int i=0; i<max_sect; i++)
1881 sect_flag[i] = false;
1882
1883 // Read track
1884 uint8 act_track[21 * 256];
1885 for (int i=0; i<max_sect; i++) {
1886
1887 // Read and verify track/sector number
1888 uint8 t = getc(in);
1889 uint8 s = getc(in);
1890 if ((t & 0x3f) != track || s >= max_sect || sect_flag[s] || feof(in))
1891 goto error;
1892 sect_flag[s] = true;
1893 uint8 *p = act_track + s * 256;
1894
1895 // Uncompress sector
1896 if (t & 0x80) {
1897 // Run-length encoded sector
1898 uint8 len = getc(in);
1899 uint8 rep = getc(in);
1900 int count = 0;
1901 for (int j=0; j<len; j++) {
1902 if (feof(in))
1903 goto error;
1904 uint8 c = getc(in);
1905 if (c != rep)
1906 p[count++] = c;
1907 else {
1908 uint8 repnum = getc(in);
1909 if (feof(in))
1910 goto error;
1911 c = getc(in);
1912 j += 2;
1913 for (int k=0; k<repnum; k++)
1914 p[count++] = c;
1915 }
1916 }
1917 } else if (t & 0x40) {
1918 // Sector filled with constant byte
1919 if (feof(in))
1920 goto error;
1921 uint8 c = getc(in);
1922 memset(p, c, 256);
1923 } else {
1924 // Plain sector
1925 if (fread(p, 1, 256, in) != 256)
1926 goto error;
1927 }
1928 }
1929
1930 // Write track
1931 if (fwrite(act_track, 256, max_sect, out) != (size_t)max_sect)
1932 goto error;
1933 }
1934
1935 // Write header ID
1936 putc(id1, out);
1937 putc(id2, out);
1938
1939 // Done
1940 fclose(in);
1941 fseek(out, 0, SEEK_SET);
1942 return out;
1943
1944 error:
1945 if (in)
1946 fclose(in);
1947 if (out)
1948 fclose(out);
1949 return NULL;
1950 }
1951 #endif
1952
1953
1954 /*
1955 * Open disk image file, return file handle
1956 */
1957
1958 FILE *open_image_file(const char *path, bool write_mode)
1959 {
1960 #if 0
1961 if (is_zipcode_file(path)) {
1962 if (write_mode)
1963 return NULL;
1964 else
1965 return convert_zipcode_to_ed64(path);
1966 } else
1967 #endif
1968 return fopen(path, write_mode ? "r+b" : "rb");
1969 }
1970
1971
1972 /*
1973 * Parse image file and fill in image_file_desc structure
1974 */
1975
1976 static bool parse_d64_file(FILE *f, image_file_desc &desc, bool has_header_id)
1977 {
1978 // .d64 files have no header
1979 desc.type = has_header_id ? TYPE_ED64 : TYPE_D64;
1980 desc.header_size = 0;
1981
1982 // Determine number of tracks
1983 fseek(f, 0, SEEK_END);
1984 long size = ftell(f);
1985 if (size == NUM_SECTORS_40 * 256 || size == NUM_SECTORS_40 * 257)
1986 desc.num_tracks = 40;
1987 else
1988 desc.num_tracks = 35;
1989
1990 if (has_header_id) {
1991 // Read header ID from image file (last 2 bytes)
1992 fseek(f, -2, SEEK_END);
1993 desc.id1 = getc(f);
1994 desc.id2 = getc(f);
1995 } else {
1996 // Read header ID from BAM (use error_info as buffer)
1997 fseek(f, accum_num_sectors[18] * 256, SEEK_SET);
1998 fread(desc.error_info, 1, 256, f);
1999 desc.id1 = desc.error_info[BAM_DISK_ID];
2000 desc.id2 = desc.error_info[BAM_DISK_ID + 1];
2001 }
2002
2003 // Read error info
2004 memset(desc.error_info, 1, sizeof(desc.error_info));
2005 if (size == NUM_SECTORS_35 * 257) {
2006 fseek(f, NUM_SECTORS_35 * 256, SEEK_SET);
2007 fread(desc.error_info, NUM_SECTORS_35, 1, f);
2008 desc.has_error_info = true;
2009 } else if (size == NUM_SECTORS_40 * 257) {
2010 fseek(f, NUM_SECTORS_40 * 256, SEEK_SET);
2011 fread(desc.error_info, NUM_SECTORS_40, 1, f);
2012 desc.has_error_info = true;
2013 } else
2014 desc.has_error_info = false;
2015
2016 return true;
2017 }
2018
2019 static bool parse_x64_file(FILE *f, image_file_desc &desc)
2020 {
2021 desc.type = TYPE_X64;
2022 desc.header_size = 64;
2023
2024 // Read number of tracks
2025 fseek(f, 7, SEEK_SET);
2026 desc.num_tracks = getc(f);
2027 if (desc.num_tracks < 35 || desc.num_tracks > 40)
2028 return false;
2029
2030 // Read header ID from BAM (use error_info as buffer)
2031 fseek(f, desc.header_size + accum_num_sectors[18] * 256, SEEK_SET);
2032 fread(desc.error_info, 1, 256, f);
2033 desc.id1 = desc.error_info[BAM_DISK_ID];
2034 desc.id2 = desc.error_info[BAM_DISK_ID + 1];
2035
2036 // .x64 files have no error info
2037 memset(desc.error_info, 1, sizeof(desc.error_info));
2038 desc.has_error_info = false;
2039 return true;
2040 }
2041
2042 bool parse_image_file(FILE *f, image_file_desc &desc)
2043 {
2044 // Read header
2045 uint8 header[64];
2046 fread(header, 1, sizeof(header), f);
2047
2048 // Determine file size
2049 fseek(f, 0, SEEK_END);
2050 long size = ftell(f);
2051
2052 // Determine file type and fill in image_file_desc structure
2053 if (is_x64_file(header, size))
2054 return parse_x64_file(f, desc);
2055 else if (is_d64_file(header, size))
2056 return parse_d64_file(f, desc, false);
2057 else if (is_ed64_file(header, size))
2058 return parse_d64_file(f, desc, true);
2059 else
2060 return false;
2061 }
2062
2063
2064 /*
2065 * Create new blank disk image file, returns false on error
2066 */
2067
2068 bool CreateImageFile(const char *path)
2069 {
2070 // Open file for writing
2071 FILE *f = fopen(path, "wb");
2072 if (f == NULL)
2073 return false;
2074
2075 // Create descriptor
2076 image_file_desc desc;
2077 desc.type = TYPE_D64;
2078 desc.header_size = 0;
2079 desc.num_tracks = 35;
2080 desc.id1 = 'F';
2081 desc.id1 = 'R';
2082 memset(desc.error_info, 1, sizeof(desc.error_info));
2083 desc.has_error_info = false;
2084
2085 // Format image file
2086 if (!format_image(f, desc, true, 'F', 'R', (uint8 *)"D64 FILE", 8)) {
2087 fclose(f);
2088 remove(path);
2089 return false;
2090 }
2091
2092 // Close file
2093 fclose(f);
2094 return true;
2095 }