ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/1541d64.cpp
Revision: 1.2
Committed: 2003-07-01T17:51:17Z (21 years, 4 months ago) by cebix
Branch: MAIN
Changes since 1.1: +1 -1 lines
Log Message:
updated copyright date

File Contents

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