ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/1541d64.cpp
Revision: 1.5
Committed: 2004-01-11T14:03:29Z (20 years, 2 months ago) by cebix
Branch: MAIN
Changes since 1.4: +1571 -318 lines
Log Message:
added D64 write support

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