ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/1541d64.cpp
Revision: 1.3
Committed: 2003-07-02T14:46:24Z (20 years, 8 months ago) by cebix
Branch: MAIN
Changes since 1.2: +2 -1 lines
Log Message:
when the ROM files are not found, builtin defaults are used

File Contents

# Content
1 /*
2 * 1541d64.cpp - 1541 emulation in .d64 file
3 *
4 * Frodo (C) 1994-1997,2002-2003 Christian Bauer
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 /*
22 * Incompatibilities:
23 * ------------------
24 *
25 * - Only read accesses possible
26 * - Not all commands implemented
27 * - The .d64 error info is read, but unused
28 */
29
30 #include "sysdeps.h"
31
32 #include "1541d64.h"
33 #include "IEC.h"
34 #include "Prefs.h"
35 #include "C64.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
43 CHMOD_FILE, // Sequential file open
44 CHMOD_DIRECT // Direct buffer access ('#')
45 };
46
47 // Access modes
48 enum {
49 FMODE_READ, FMODE_WRITE, FMODE_APPEND
50 };
51
52 // File types
53 enum {
54 FTYPE_PRG, FTYPE_SEQ, FTYPE_USR, FTYPE_REL
55 };
56
57 // Number of tracks/sectors
58 const int NUM_TRACKS = 35;
59 const int NUM_SECTORS = 683;
60
61 // Prototypes
62 static bool match(uint8 *p, uint8 *n);
63
64
65 /*
66 * Constructor: Prepare emulation, open .d64 file
67 */
68
69 D64Drive::D64Drive(IEC *iec, char *filepath) : Drive(iec)
70 {
71 the_file = NULL;
72 ram = NULL;
73
74 Ready = false;
75 strcpy(orig_d64_name, filepath);
76 for (int i=0; i<=14; i++) {
77 chan_mode[i] = CHMOD_FREE;
78 chan_buf[i] = NULL;
79 }
80 chan_mode[15] = CHMOD_COMMAND;
81
82 // Open .d64 file
83 open_close_d64_file(filepath);
84 if (the_file != NULL) {
85
86 // Allocate 1541 RAM
87 ram = new uint8[DRIVE_RAM_SIZE];
88 bam = (BAM *)(ram + 0x700);
89
90 Reset();
91 Ready = true;
92 }
93 }
94
95
96 /*
97 * Destructor
98 */
99
100 D64Drive::~D64Drive()
101 {
102 // Close .d64 file
103 open_close_d64_file("");
104
105 delete[] ram;
106 Ready = false;
107 }
108
109
110 /*
111 * Open/close the .d64 file
112 */
113
114 void D64Drive::open_close_d64_file(char *d64name)
115 {
116 long size;
117 uint8 magic[4];
118
119 // Close old .d64, if open
120 if (the_file != NULL) {
121 close_all_channels();
122 fclose(the_file);
123 the_file = NULL;
124 }
125
126 // Open new .d64 file
127 if (d64name[0]) {
128 if ((the_file = fopen(d64name, "rb")) != NULL) {
129
130 // Check length
131 fseek(the_file, 0, SEEK_END);
132 if ((size = ftell(the_file)) < NUM_SECTORS * 256) {
133 fclose(the_file);
134 the_file = NULL;
135 return;
136 }
137
138 // x64 image?
139 rewind(the_file);
140 fread(&magic, 4, 1, the_file);
141 if (magic[0] == 0x43 && magic[1] == 0x15 && magic[2] == 0x41 && magic[3] == 0x64)
142 image_header = 64;
143 else
144 image_header = 0;
145
146 // Preset error info (all sectors no error)
147 memset(error_info, 1, NUM_SECTORS);
148
149 // Load sector error info from .d64 file, if present
150 if (!image_header && size == NUM_SECTORS * 257) {
151 fseek(the_file, NUM_SECTORS * 256, SEEK_SET);
152 fread(&error_info, NUM_SECTORS, 1, the_file);
153 }
154 }
155 }
156 }
157
158
159 /*
160 * Open channel
161 */
162
163 uint8 D64Drive::Open(int channel, char *filename)
164 {
165 set_error(ERR_OK);
166
167 // Channel 15: execute file name as command
168 if (channel == 15) {
169 execute_command(filename);
170 return ST_OK;
171 }
172
173 if (chan_mode[channel] != CHMOD_FREE) {
174 set_error(ERR_NOCHANNEL);
175 return ST_OK;
176 }
177
178 if (filename[0] == '$')
179 if (channel)
180 return open_file_ts(channel, 18, 0);
181 else
182 return open_directory(filename+1);
183
184 if (filename[0] == '#')
185 return open_direct(channel, filename);
186
187 return open_file(channel, filename);
188 }
189
190
191 /*
192 * Open file
193 */
194
195 uint8 D64Drive::open_file(int channel, char *filename)
196 {
197 char plainname[256];
198 int filemode = FMODE_READ;
199 int filetype = FTYPE_PRG;
200 int track, sector;
201
202 convert_filename(filename, plainname, &filemode, &filetype);
203
204 // Channel 0 is READ PRG, channel 1 is WRITE PRG
205 if (!channel) {
206 filemode = FMODE_READ;
207 filetype = FTYPE_PRG;
208 }
209 if (channel == 1) {
210 filemode = FMODE_WRITE;
211 filetype = FTYPE_PRG;
212 }
213
214 // Allow only read accesses
215 if (filemode != FMODE_READ) {
216 set_error(ERR_WRITEPROTECT);
217 return ST_OK;
218 }
219
220 // Find file in directory and open it
221 if (find_file(plainname, &track, &sector))
222 return open_file_ts(channel, track, sector);
223 else
224 set_error(ERR_FILENOTFOUND);
225
226 return ST_OK;
227 }
228
229
230 /*
231 * Analyze file name, get access mode and type
232 */
233
234 void D64Drive::convert_filename(char *srcname, char *destname, int *filemode, int *filetype)
235 {
236 char *p;
237
238 // Search for ':', p points to first character after ':'
239 if ((p = strchr(srcname, ':')) != NULL)
240 p++;
241 else
242 p = srcname;
243
244 // Remaining string -> destname
245 strncpy(destname, p, NAMEBUF_LENGTH);
246
247 // Search for ','
248 p = destname;
249 while (*p && (*p != ',')) p++;
250
251 // Look for mode parameters seperated by ','
252 p = destname;
253 while ((p = strchr(p, ',')) != NULL) {
254
255 // Cut string after the first ','
256 *p++ = 0;
257
258 switch (*p) {
259 case 'P':
260 *filetype = FTYPE_PRG;
261 break;
262 case 'S':
263 *filetype = FTYPE_SEQ;
264 break;
265 case 'U':
266 *filetype = FTYPE_USR;
267 break;
268 case 'L':
269 *filetype = FTYPE_REL;
270 break;
271 case 'R':
272 *filemode = FMODE_READ;
273 break;
274 case 'W':
275 *filemode = FMODE_WRITE;
276 break;
277 case 'A':
278 *filemode = FMODE_APPEND;
279 break;
280 }
281 }
282 }
283
284
285 /*
286 * Search file in directory, find first track and sector
287 * false: not found, true: found
288 */
289
290 bool D64Drive::find_file(char *filename, int *track, int *sector)
291 {
292 int i, j;
293 uint8 *p, *q;
294 DirEntry *de;
295
296 // Scan all directory blocks
297 dir.next_track = bam->dir_track;
298 dir.next_sector = bam->dir_sector;
299
300 while (dir.next_track) {
301 if (!read_sector(dir.next_track, dir.next_sector, (uint8 *) &dir.next_track))
302 return false;
303
304 // Scan all 8 entries of a block
305 for (j=0; j<8; j++) {
306 de = &dir.entry[j];
307 *track = de->track;
308 *sector = de->sector;
309
310 if (de->type) {
311 p = (uint8 *)filename;
312 q = de->name;
313 for (i=0; i<16 && *p; i++, p++, q++) {
314 if (*p == '*') // Wildcard '*' matches all following characters
315 return true;
316 if (*p != *q) {
317 if (*p != '?') goto next_entry; // Wildcard '?' matches single character
318 if (*q == 0xa0) goto next_entry;
319 }
320 }
321
322 if (i == 16 || *q == 0xa0)
323 return true;
324 }
325 next_entry: ;
326 }
327 }
328
329 return false;
330 }
331
332
333 /*
334 * Open file given track/sector of first block
335 */
336
337 uint8 D64Drive::open_file_ts(int channel, int track, int sector)
338 {
339 chan_buf[channel] = new uint8[256];
340 chan_mode[channel] = CHMOD_FILE;
341
342 // On the next call to Read, the first block will be read
343 chan_buf[channel][0] = track;
344 chan_buf[channel][1] = sector;
345 buf_len[channel] = 0;
346
347 return ST_OK;
348 }
349
350
351 /*
352 * Prepare directory as BASIC program (channel 0)
353 */
354
355 const char type_char_1[] = "DSPUREERSELQGRL?";
356 const char type_char_2[] = "EERSELQGRL??????";
357 const char type_char_3[] = "LQGRL???????????";
358
359 // Return true if name 'n' matches pattern 'p'
360 static bool match(uint8 *p, uint8 *n)
361 {
362 if (!*p) // Null pattern matches everything
363 return true;
364
365 do {
366 if (*p == '*') // Wildcard '*' matches all following characters
367 return true;
368 if ((*p != *n) && (*p != '?')) // Wildcard '?' matches single character
369 return false;
370 p++; n++;
371 } while (*p);
372
373 return *n == 0xa0;
374 }
375
376 uint8 D64Drive::open_directory(char *pattern)
377 {
378 int i, j, n, m;
379 uint8 *p, *q;
380 DirEntry *de;
381 uint8 c;
382 char *tmppat;
383
384 // Special treatment for "$0"
385 if (pattern[0] == '0' && pattern[1] == 0)
386 pattern += 1;
387
388 // Skip everything before the ':' in the pattern
389 if ((tmppat = strchr(pattern, ':')) != NULL)
390 pattern = tmppat + 1;
391
392 p = buf_ptr[0] = chan_buf[0] = new uint8[8192];
393 chan_mode[0] = CHMOD_DIRECTORY;
394
395 // Create directory title
396 *p++ = 0x01; // Load address $0401 (from PET days :-)
397 *p++ = 0x04;
398 *p++ = 0x01; // Dummy line link
399 *p++ = 0x01;
400 *p++ = 0; // Drive number (0) as line number
401 *p++ = 0;
402 *p++ = 0x12; // RVS ON
403 *p++ = '\"';
404
405 q = bam->disk_name;
406 for (i=0; i<23; i++) {
407 if ((c = *q++) == 0xa0)
408 *p++ = ' '; // Replace 0xa0 by space
409 else
410 *p++ = c;
411 }
412 *(p-7) = '\"';
413 *p++ = 0;
414
415 // Scan all directory blocks
416 dir.next_track = bam->dir_track;
417 dir.next_sector = bam->dir_sector;
418
419 while (dir.next_track) {
420 if (!read_sector(dir.next_track, dir.next_sector, (uint8 *) &dir.next_track))
421 return ST_OK;
422
423 // Scan all 8 entries of a block
424 for (j=0; j<8; j++) {
425 de = &dir.entry[j];
426
427 if (de->type && match((uint8 *)pattern, de->name)) {
428 *p++ = 0x01; // Dummy line link
429 *p++ = 0x01;
430
431 *p++ = de->num_blocks_l; // Line number
432 *p++ = de->num_blocks_h;
433
434 *p++ = ' ';
435 n = (de->num_blocks_h << 8) + de->num_blocks_l;
436 if (n<10) *p++ = ' ';
437 if (n<100) *p++ = ' ';
438
439 *p++ = '\"';
440 q = de->name;
441 m = 0;
442 for (i=0; i<16; i++) {
443 if ((c = *q++) == 0xa0) {
444 if (m)
445 *p++ = ' '; // Replace all 0xa0 by spaces
446 else
447 m = *p++ = '\"'; // But the first by a '"'
448 } else
449 *p++ = c;
450 }
451 if (m)
452 *p++ = ' ';
453 else
454 *p++ = '\"'; // No 0xa0, then append a space
455
456 if (de->type & 0x80)
457 *p++ = ' ';
458 else
459 *p++ = '*';
460
461 *p++ = type_char_1[de->type & 0x0f];
462 *p++ = type_char_2[de->type & 0x0f];
463 *p++ = type_char_3[de->type & 0x0f];
464
465 if (de->type & 0x40)
466 *p++ = '<';
467 else
468 *p++ = ' ';
469
470 *p++ = ' ';
471 if (n >= 10) *p++ = ' ';
472 if (n >= 100) *p++ = ' ';
473 *p++ = 0;
474 }
475 }
476 }
477
478 // Final line
479 q = p;
480 for (i=0; i<29; i++)
481 *q++ = ' ';
482
483 n = 0;
484 for (i=0; i<35; i++)
485 n += bam->bitmap[i*4];
486
487 *p++ = 0x01; // Dummy line link
488 *p++ = 0x01;
489 *p++ = n & 0xff; // Number of free blocks as line number
490 *p++ = (n >> 8) & 0xff;
491
492 *p++ = 'B';
493 *p++ = 'L';
494 *p++ = 'O';
495 *p++ = 'C';
496 *p++ = 'K';
497 *p++ = 'S';
498 *p++ = ' ';
499 *p++ = 'F';
500 *p++ = 'R';
501 *p++ = 'E';
502 *p++ = 'E';
503 *p++ = '.';
504
505 p = q;
506 *p++ = 0;
507 *p++ = 0;
508 *p++ = 0;
509
510 buf_len[0] = p - chan_buf[0];
511
512 return ST_OK;
513 }
514
515
516 /*
517 * Open channel for direct buffer access
518 */
519
520 uint8 D64Drive::open_direct(int channel, char *filename)
521 {
522 int buf = -1;
523
524 if (filename[1] == 0)
525 buf = alloc_buffer(-1);
526 else
527 if ((filename[1] >= '0') && (filename[1] <= '3') && (filename[2] == 0))
528 buf = alloc_buffer(filename[1] - '0');
529
530 if (buf == -1) {
531 set_error(ERR_NOCHANNEL);
532 return ST_OK;
533 }
534
535 // The buffers are in the 1541 RAM at $300 and are 256 bytes each
536 chan_buf[channel] = buf_ptr[channel] = ram + 0x300 + (buf << 8);
537 chan_mode[channel] = CHMOD_DIRECT;
538 chan_buf_num[channel] = buf;
539
540 // Store actual buffer number in buffer
541 *chan_buf[channel] = buf + '0';
542 buf_len[channel] = 1;
543
544 return ST_OK;
545 }
546
547
548 /*
549 * Close channel
550 */
551
552 uint8 D64Drive::Close(int channel)
553 {
554 if (channel == 15) {
555 close_all_channels();
556 return ST_OK;
557 }
558
559 switch (chan_mode[channel]) {
560 case CHMOD_FREE:
561 break;
562
563 case CHMOD_DIRECT:
564 free_buffer(chan_buf_num[channel]);
565 chan_buf[channel] = NULL;
566 chan_mode[channel] = CHMOD_FREE;
567 break;
568
569 default:
570 delete[] chan_buf[channel];
571 chan_buf[channel] = NULL;
572 chan_mode[channel] = CHMOD_FREE;
573 break;
574 }
575
576 return ST_OK;
577 }
578
579
580 /*
581 * Close all channels
582 */
583
584 void D64Drive::close_all_channels()
585 {
586 for (int i=0; i<15; i++)
587 Close(i);
588
589 cmd_len = 0;
590 }
591
592
593 /*
594 * Read from channel
595 */
596
597 uint8 D64Drive::Read(int channel, uint8 *byte)
598 {
599 switch (chan_mode[channel]) {
600 case CHMOD_COMMAND:
601 *byte = *error_ptr++;
602 if (--error_len)
603 return ST_OK;
604 else {
605 set_error(ERR_OK);
606 return ST_EOF;
607 }
608 break;
609
610 case CHMOD_FILE:
611 // Read next block if necessary
612 if (chan_buf[channel][0] && !buf_len[channel]) {
613 if (!read_sector(chan_buf[channel][0], chan_buf[channel][1], chan_buf[channel]))
614 return ST_READ_TIMEOUT;
615 buf_ptr[channel] = chan_buf[channel] + 2;
616
617 // Determine block length
618 buf_len[channel] = chan_buf[channel][0] ? 254 : (uint8)chan_buf[channel][1]-1;
619 }
620
621 if (buf_len[channel] > 0) {
622 *byte = *buf_ptr[channel]++;
623 if (!--buf_len[channel] && !chan_buf[channel][0])
624 return ST_EOF;
625 else
626 return ST_OK;
627 } else
628 return ST_READ_TIMEOUT;
629 break;
630
631 case CHMOD_DIRECTORY:
632 case CHMOD_DIRECT:
633 if (buf_len[channel] > 0) {
634 *byte = *buf_ptr[channel]++;
635 if (--buf_len[channel])
636 return ST_OK;
637 else
638 return ST_EOF;
639 } else
640 return ST_READ_TIMEOUT;
641 break;
642 }
643 return ST_READ_TIMEOUT;
644 }
645
646
647 /*
648 * Write byte to channel
649 */
650
651 uint8 D64Drive::Write(int channel, uint8 byte, bool eoi)
652 {
653 switch (chan_mode[channel]) {
654 case CHMOD_FREE:
655 set_error(ERR_FILENOTOPEN);
656 break;
657
658 case CHMOD_COMMAND:
659 // Collect characters and execute command on EOI
660 if (cmd_len >= 40)
661 return ST_TIMEOUT;
662
663 cmd_buffer[cmd_len++] = byte;
664
665 if (eoi) {
666 cmd_buffer[cmd_len++] = 0;
667 cmd_len = 0;
668 execute_command(cmd_buffer);
669 }
670 return ST_OK;
671
672 case CHMOD_DIRECTORY:
673 set_error(ERR_WRITEFILEOPEN);
674 break;
675 }
676 return ST_TIMEOUT;
677 }
678
679
680 /*
681 * Execute command string
682 */
683
684 void D64Drive::execute_command(char *command)
685 {
686 uint16 adr;
687 int len;
688
689 switch (command[0]) {
690 case 'B':
691 if (command[1] != '-')
692 set_error(ERR_SYNTAX30);
693 else
694 switch (command[2]) {
695 case 'R':
696 block_read_cmd(&command[3]);
697 break;
698
699 case 'P':
700 buffer_ptr_cmd(&command[3]);
701 break;
702
703 case 'A':
704 case 'F':
705 case 'W':
706 set_error(ERR_WRITEPROTECT);
707 break;
708
709 default:
710 set_error(ERR_SYNTAX30);
711 break;
712 }
713 break;
714
715 case 'M':
716 if (command[1] != '-')
717 set_error(ERR_SYNTAX30);
718 else
719 switch (command[2]) {
720 case 'R':
721 adr = ((uint8)command[4] << 8) | ((uint8)command[3]);
722 error_ptr = (char *)(ram + (adr & 0x07ff));
723 if (!(error_len = (uint8)command[5]))
724 error_len = 1;
725 break;
726
727 case 'W':
728 adr = ((uint8)command[4] << 8) | ((uint8)command[3]);
729 len = (uint8)command[5];
730 for (int i=0; i<len; i++)
731 ram[adr+i] = (uint8)command[i+6];
732 break;
733
734 default:
735 set_error(ERR_SYNTAX30);
736 }
737 break;
738
739 case 'I':
740 close_all_channels();
741 read_sector(18, 0, (uint8 *)bam);
742 set_error(ERR_OK);
743 break;
744
745 case 'U':
746 switch (command[1] & 0x0f) {
747 case 1: // U1/UA: Block-Read
748 block_read_cmd(&command[2]);
749 break;
750
751 case 2: // U2/UB: Block-Write
752 set_error(ERR_WRITEPROTECT);
753 break;
754
755 case 10: // U:/UJ: Reset
756 Reset();
757 break;
758
759 default:
760 set_error(ERR_SYNTAX30);
761 break;
762 }
763 break;
764
765 case 'G':
766 if (command[1] != ':')
767 set_error(ERR_SYNTAX30);
768 else
769 chd64_cmd(&command[2]);
770 break;
771
772 case 'C':
773 case 'N':
774 case 'R':
775 case 'S':
776 case 'V':
777 set_error(ERR_WRITEPROTECT);
778 break;
779
780 default:
781 set_error(ERR_SYNTAX30);
782 break;
783 }
784 }
785
786
787 /*
788 * Execute B-R command
789 */
790
791 void D64Drive::block_read_cmd(char *command)
792 {
793 int channel, drvnum, track, sector;
794
795 if (parse_bcmd(command, &channel, &drvnum, &track, &sector)) {
796 if (chan_mode[channel] == CHMOD_DIRECT) {
797 read_sector(track, sector, buf_ptr[channel] = chan_buf[channel]);
798 buf_len[channel] = 256;
799 set_error(ERR_OK);
800 } else
801 set_error(ERR_NOCHANNEL);
802 } else
803 set_error(ERR_SYNTAX30);
804 }
805
806
807 /*
808 * Execute B-P command
809 */
810
811 void D64Drive::buffer_ptr_cmd(char *command)
812 {
813 int channel, pointer, i;
814
815 if (parse_bcmd(command, &channel, &pointer, &i, &i)) {
816 if (chan_mode[channel] == CHMOD_DIRECT) {
817 buf_ptr[channel] = chan_buf[channel] + pointer;
818 buf_len[channel] = 256 - pointer;
819 set_error(ERR_OK);
820 } else
821 set_error(ERR_NOCHANNEL);
822 } else
823 set_error(ERR_SYNTAX30);
824 }
825
826
827 /*
828 * Parse block command parameters
829 * true: OK, false: error
830 */
831
832 bool D64Drive::parse_bcmd(char *cmd, int *arg1, int *arg2, int *arg3, int *arg4)
833 {
834 int i;
835
836 if (*cmd == ':') cmd++;
837
838 // Read four parameters separated by space, cursor right or comma
839 while (*cmd == ' ' || *cmd == 0x1d || *cmd == 0x2c) cmd++;
840 if (!*cmd) return false;
841
842 i = 0;
843 while (*cmd >= 0x30 && *cmd < 0x40) {
844 i *= 10;
845 i += *cmd++ & 0x0f;
846 }
847 *arg1 = i & 0xff;
848
849 while (*cmd == ' ' || *cmd == 0x1d || *cmd == 0x2c) cmd++;
850 if (!*cmd) return false;
851
852 i = 0;
853 while (*cmd >= 0x30 && *cmd < 0x40) {
854 i *= 10;
855 i += *cmd++ & 0x0f;
856 }
857 *arg2 = i & 0xff;
858
859 while (*cmd == ' ' || *cmd == 0x1d || *cmd == 0x2c) cmd++;
860 if (!*cmd) return false;
861
862 i = 0;
863 while (*cmd >= 0x30 && *cmd < 0x40) {
864 i *= 10;
865 i += *cmd++ & 0x0f;
866 }
867 *arg3 = i & 0xff;
868
869 while (*cmd == ' ' || *cmd == 0x1d || *cmd == 0x2c) cmd++;
870 if (!*cmd) return false;
871
872 i = 0;
873 while (*cmd >= 0x30 && *cmd < 0x40) {
874 i *= 10;
875 i += *cmd++ & 0x0f;
876 }
877 *arg4 = i & 0xff;
878
879 return true;
880 }
881
882
883 /*
884 * Execute 'G' command
885 */
886
887 void D64Drive::chd64_cmd(char *d64name)
888 {
889 char str[NAMEBUF_LENGTH];
890 char *p = str;
891
892 // Convert .d64 file name
893 for (int i=0; i<NAMEBUF_LENGTH && (*p++ = conv_from_64(*d64name++, false)); i++) ;
894
895 close_all_channels();
896
897 // G:. resets the .d64 file name to its original setting
898 if (str[0] == '.' && str[1] == 0)
899 open_close_d64_file(orig_d64_name);
900 else
901 open_close_d64_file(str);
902
903 // Read BAM
904 read_sector(18, 0, (uint8 *)bam);
905 }
906
907
908 /*
909 * Reset drive
910 */
911
912 void D64Drive::Reset(void)
913 {
914 close_all_channels();
915
916 read_sector(18, 0, (uint8 *)bam);
917
918 cmd_len = 0;
919 for (int i=0; i<4; i++)
920 buf_free[i] = true;
921
922 set_error(ERR_STARTUP);
923 }
924
925
926 /*
927 * Allocate floppy buffer
928 * -> Desired buffer number or -1
929 * <- Allocated buffer number or -1
930 */
931
932 int D64Drive::alloc_buffer(int want)
933 {
934 if (want == -1) {
935 for (want=3; want>=0; want--)
936 if (buf_free[want]) {
937 buf_free[want] = false;
938 return want;
939 }
940 return -1;
941 }
942
943 if (want < 4)
944 if (buf_free[want]) {
945 buf_free[want] = false;
946 return want;
947 } else
948 return -1;
949 else
950 return -1;
951 }
952
953
954 /*
955 * Free floppy buffer
956 */
957
958 void D64Drive::free_buffer(int buf)
959 {
960 buf_free[buf] = true;
961 }
962
963
964 /*
965 * Read sector (256 bytes)
966 * true: success, false: error
967 */
968
969 bool D64Drive::read_sector(int track, int sector, uint8 *buffer)
970 {
971 int offset;
972
973 // Convert track/sector to byte offset in file
974 if ((offset = offset_from_ts(track, sector)) < 0) {
975 set_error(ERR_ILLEGALTS);
976 return false;
977 }
978
979 if (the_file == NULL) {
980 set_error(ERR_NOTREADY);
981 return false;
982 }
983
984 #ifdef AMIGA
985 if (offset != ftell(the_file))
986 fseek(the_file, offset + image_header, SEEK_SET);
987 #else
988 fseek(the_file, offset + image_header, SEEK_SET);
989 #endif
990 fread(buffer, 256, 1, the_file);
991 return true;
992 }
993
994
995 /*
996 * Convert track/sector to offset
997 */
998
999 const int num_sectors[41] = {
1000 0,
1001 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,
1002 19,19,19,19,19,19,19,
1003 18,18,18,18,18,18,
1004 17,17,17,17,17,
1005 17,17,17,17,17 // Tracks 36..40
1006 };
1007
1008 const int sector_offset[41] = {
1009 0,
1010 0,21,42,63,84,105,126,147,168,189,210,231,252,273,294,315,336,
1011 357,376,395,414,433,452,471,
1012 490,508,526,544,562,580,
1013 598,615,632,649,666,
1014 683,700,717,734,751 // Tracks 36..40
1015 };
1016
1017 int D64Drive::offset_from_ts(int track, int sector)
1018 {
1019 if ((track < 1) || (track > NUM_TRACKS) ||
1020 (sector < 0) || (sector >= num_sectors[track]))
1021 return -1;
1022
1023 return (sector_offset[track] + sector) << 8;
1024 }
1025
1026
1027 /*
1028 * Conversion PETSCII->ASCII
1029 */
1030
1031 uint8 D64Drive::conv_from_64(uint8 c, bool map_slash)
1032 {
1033 if ((c >= 'A') && (c <= 'Z') || (c >= 'a') && (c <= 'z'))
1034 return c ^ 0x20;
1035 if ((c >= 0xc1) && (c <= 0xda))
1036 return c ^ 0x80;
1037 if ((c == '/') && map_slash && ThePrefs.MapSlash)
1038 return '\\';
1039 return c;
1040 }