ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/1541d64.cpp
(Generate patch)

Comparing Frodo4/Src/1541d64.cpp (file contents):
Revision 1.1 by cebix, 2003-07-01T17:09:43Z vs.
Revision 1.4 by cebix, 2004-01-11T00:09:51Z

# Line 1 | Line 1
1   /*
2   *  1541d64.cpp - 1541 emulation in .d64 file
3   *
4 < *  Frodo (C) 1994-1997,2002 Christian Bauer
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
# Line 32 | Line 32
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 :-)
# Line 43 | Line 44 | enum {
44          CHMOD_DIRECT            // Direct buffer access ('#')
45   };
46  
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
47   // Number of tracks/sectors
48   const int NUM_TRACKS = 35;
49   const int NUM_SECTORS = 683;
# Line 83 | Line 74 | D64Drive::D64Drive(IEC *iec, char *filep
74          if (the_file != NULL) {
75  
76                  // Allocate 1541 RAM
77 <                ram = new uint8[0x800];
77 >                ram = new uint8[DRIVE_RAM_SIZE];
78                  bam = (BAM *)(ram + 0x700);
79  
80                  Reset();
# Line 159 | Line 150 | void D64Drive::open_close_d64_file(char
150   *  Open channel
151   */
152  
153 < uint8 D64Drive::Open(int channel, char *filename)
153 > uint8 D64Drive::Open(int channel, const uint8 *name, int name_len)
154   {
155          set_error(ERR_OK);
156  
157          // Channel 15: execute file name as command
158          if (channel == 15) {
159 <                execute_command(filename);
159 >                execute_cmd(name, name_len);
160                  return ST_OK;
161          }
162  
# Line 174 | Line 165 | uint8 D64Drive::Open(int channel, char *
165                  return ST_OK;
166          }
167  
168 <        if (filename[0] == '$')
168 >        if (name[0] == '$')
169                  if (channel)
170                          return open_file_ts(channel, 18, 0);
171                  else
172 <                        return open_directory(filename+1);
172 >                        return open_directory(name + 1, name_len - 1);
173  
174 <        if (filename[0] == '#')
175 <                return open_direct(channel, filename);
174 >        if (name[0] == '#')
175 >                return open_direct(channel, name);
176  
177 <        return open_file(channel, filename);
177 >        return open_file(channel, name, name_len);
178   }
179  
180  
# Line 191 | Line 182 | uint8 D64Drive::Open(int channel, char *
182   *  Open file
183   */
184  
185 < uint8 D64Drive::open_file(int channel, char *filename)
185 > uint8 D64Drive::open_file(int channel, const uint8 *name, int name_len)
186   {
187 <        char plainname[256];
188 <        int filemode = FMODE_READ;
189 <        int filetype = FTYPE_PRG;
190 <        int track, sector;
191 <
192 <        convert_filename(filename, plainname, &filemode, &filetype);
193 <
194 <        // Channel 0 is READ PRG, channel 1 is WRITE PRG
195 <        if (!channel) {
196 <                filemode = FMODE_READ;
197 <                filetype = FTYPE_PRG;
198 <        }
199 <        if (channel == 1) {
200 <                filemode = FMODE_WRITE;
210 <                filetype = FTYPE_PRG;
187 >        uint8 plain_name[256];
188 >        int plain_name_len;
189 >        int mode = FMODE_READ;
190 >        int type = FTYPE_PRG;
191 >        int rec_len = 0;
192 >        parse_file_name(name, name_len, plain_name, plain_name_len, mode, type, rec_len);
193 >        if (plain_name_len > 16)
194 >                plain_name_len = 16;
195 >
196 >        // Channel 0 is READ, channel 1 is WRITE
197 >        if (channel == 0 || channel == 1) {
198 >                mode = channel ? FMODE_WRITE : FMODE_READ;
199 >                if (type == FTYPE_DEL)
200 >                        type = FTYPE_PRG;
201          }
202  
203          // Allow only read accesses
204 <        if (filemode != FMODE_READ) {
204 >        if (mode != FMODE_READ) {
205                  set_error(ERR_WRITEPROTECT);
206                  return ST_OK;
207          }
208  
209 +        // Relative files are not supported
210 +        if (type == FTYPE_REL) {
211 +                set_error(ERR_UNIMPLEMENTED);
212 +                return ST_OK;
213 +        }
214 +
215          // Find file in directory and open it
216 <        if (find_file(plainname, &track, &sector))
216 >        int track, sector;
217 >        if (find_file(plain_name, &track, &sector))
218                  return open_file_ts(channel, track, sector);
219          else
220                  set_error(ERR_FILENOTFOUND);
# Line 227 | Line 224 | uint8 D64Drive::open_file(int channel, c
224  
225  
226   /*
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 /*
227   *  Search file in directory, find first track and sector
228   *  false: not found, true: found
229   */
230  
231 < bool D64Drive::find_file(char *filename, int *track, int *sector)
231 > bool D64Drive::find_file(const uint8 *pattern, int *track, int *sector)
232   {
233          int i, j;
234 <        uint8 *p, *q;
234 >        const uint8 *p, *q;
235          DirEntry *de;
236  
237          // Scan all directory blocks
# Line 307 | Line 249 | bool D64Drive::find_file(char *filename,
249                          *sector = de->sector;
250  
251                          if (de->type) {
252 <                                p = (uint8 *)filename;
252 >                                p = pattern;
253                                  q = de->name;
254                                  for (i=0; i<16 && *p; i++, p++, q++) {
255                                          if (*p == '*')  // Wildcard '*' matches all following characters
# Line 372 | Line 314 | static bool match(uint8 *p, uint8 *n)
314          return *n == 0xa0;
315   }
316  
317 < uint8 D64Drive::open_directory(char *pattern)
317 > uint8 D64Drive::open_directory(const uint8 *pattern, int pattern_len)
318   {
377        int i, j, n, m;
378        uint8 *p, *q;
379        DirEntry *de;
380        uint8 c;
381        char *tmppat;
382
319          // Special treatment for "$0"
320 <        if (pattern[0] == '0' && pattern[1] == 0)
321 <                pattern += 1;
320 >        if (pattern[0] == '0' && pattern[1] == 0) {
321 >                pattern++;
322 >                pattern_len--;
323 >        }
324  
325          // Skip everything before the ':' in the pattern
326 <        if ((tmppat = strchr(pattern, ':')) != NULL)
327 <                pattern = tmppat + 1;
326 >        uint8 *t = (uint8 *)memchr(pattern, ':', pattern_len);
327 >        if (t) {
328 >                t++;
329 >                pattern_len -= t - pattern;
330 >                pattern = t;
331 >        }
332  
391        p = buf_ptr[0] = chan_buf[0] = new uint8[8192];
333          chan_mode[0] = CHMOD_DIRECTORY;
334 +        uint8 *p = buf_ptr[0] = chan_buf[0] = new uint8[8192];
335  
336          // Create directory title
337          *p++ = 0x01;    // Load address $0401 (from PET days :-)
# Line 401 | Line 343 | uint8 D64Drive::open_directory(char *pat
343          *p++ = 0x12;    // RVS ON
344          *p++ = '\"';
345  
346 <        q = bam->disk_name;
347 <        for (i=0; i<23; i++) {
346 >        uint8 *q = bam->disk_name;
347 >        for (int i=0; i<23; i++) {
348 >                int c;
349                  if ((c = *q++) == 0xa0)
350                          *p++ = ' ';             // Replace 0xa0 by space
351                  else
# Line 420 | Line 363 | uint8 D64Drive::open_directory(char *pat
363                          return ST_OK;
364  
365                  // Scan all 8 entries of a block
366 <                for (j=0; j<8; j++) {
367 <                        de = &dir.entry[j];
366 >                for (int j=0; j<8; j++) {
367 >                        DirEntry *de = &dir.entry[j];
368  
369                          if (de->type && match((uint8 *)pattern, de->name)) {
370                                  *p++ = 0x01; // Dummy line link
# Line 431 | Line 374 | uint8 D64Drive::open_directory(char *pat
374                                  *p++ = de->num_blocks_h;
375  
376                                  *p++ = ' ';
377 <                                n = (de->num_blocks_h << 8) + de->num_blocks_l;
377 >                                int n = (de->num_blocks_h << 8) + de->num_blocks_l;
378                                  if (n<10) *p++ = ' ';
379                                  if (n<100) *p++ = ' ';
380  
381                                  *p++ = '\"';
382                                  q = de->name;
383 <                                m = 0;
384 <                                for (i=0; i<16; i++) {
383 >                                uint8 c;
384 >                                int m = 0;
385 >                                for (int i=0; i<16; i++) {
386                                          if ((c = *q++) == 0xa0) {
387                                                  if (m)
388 <                                                        *p++ = ' ';             // Replace all 0xa0 by spaces
388 >                                                        *p++ = ' ';                     // Replace all 0xa0 by spaces
389                                                  else
390                                                          m = *p++ = '\"';        // But the first by a '"'
391                                          } else
# Line 452 | Line 396 | uint8 D64Drive::open_directory(char *pat
396                                  else
397                                          *p++ = '\"';                    // No 0xa0, then append a space
398  
399 +                                // Open files are marked by '*'
400                                  if (de->type & 0x80)
401                                          *p++ = ' ';
402                                  else
403                                          *p++ = '*';
404  
405 +                                // File type
406                                  *p++ = type_char_1[de->type & 0x0f];
407                                  *p++ = type_char_2[de->type & 0x0f];
408                                  *p++ = type_char_3[de->type & 0x0f];
409  
410 +                                // Protected files are marked by '<'
411                                  if (de->type & 0x40)
412                                          *p++ = '<';
413                                  else
414                                          *p++ = ' ';
415  
416 +                                // Appropriate number of spaces at the end
417                                  *p++ = ' ';
418                                  if (n >= 10) *p++ = ' ';
419                                  if (n >= 100) *p++ = ' ';
# Line 474 | Line 422 | uint8 D64Drive::open_directory(char *pat
422                  }
423          }
424  
425 <        // Final line
426 <        q = p;
427 <        for (i=0; i<29; i++)
428 <                *q++ = ' ';
429 <
430 <        n = 0;
483 <        for (i=0; i<35; i++)
484 <                n += bam->bitmap[i*4];
425 >        // Final line, count number of free blocks
426 >        int n = 0;
427 >        for (int i=0; i<35; i++) {
428 >                if (i != 17) // exclude directory track
429 >                        n += bam->bitmap[i*4];
430 >        }
431  
432          *p++ = 0x01;            // Dummy line link
433          *p++ = 0x01;
# Line 501 | Line 447 | uint8 D64Drive::open_directory(char *pat
447          *p++ = 'E';
448          *p++ = '.';
449  
450 <        p = q;
450 >        memset(p, ' ', 13);
451 >        p += 13;
452 >
453          *p++ = 0;
454          *p++ = 0;
455          *p++ = 0;
# Line 516 | Line 464 | uint8 D64Drive::open_directory(char *pat
464   *  Open channel for direct buffer access
465   */
466  
467 < uint8 D64Drive::open_direct(int channel, char *filename)
467 > uint8 D64Drive::open_direct(int channel, const uint8 *name)
468   {
469          int buf = -1;
470  
471 <        if (filename[1] == 0)
471 >        if (name[1] == 0)
472                  buf = alloc_buffer(-1);
473          else
474 <                if ((filename[1] >= '0') && (filename[1] <= '3') && (filename[2] == 0))
475 <                        buf = alloc_buffer(filename[1] - '0');
474 >                if ((name[1] >= '0') && (name[1] <= '3') && (name[2] == 0))
475 >                        buf = alloc_buffer(name[1] - '0');
476  
477          if (buf == -1) {
478                  set_error(ERR_NOCHANNEL);
# Line 656 | Line 604 | uint8 D64Drive::Write(int channel, uint8
604  
605                  case CHMOD_COMMAND:
606                          // Collect characters and execute command on EOI
607 <                        if (cmd_len >= 40)
607 >                        if (cmd_len >= 58)
608                                  return ST_TIMEOUT;
609  
610 <                        cmd_buffer[cmd_len++] = byte;
610 >                        cmd_buf[cmd_len++] = byte;
611  
612                          if (eoi) {
613 <                                cmd_buffer[cmd_len++] = 0;
613 >                                execute_cmd(cmd_buf, cmd_len);
614                                  cmd_len = 0;
667                                execute_command(cmd_buffer);
615                          }
616                          return ST_OK;
617  
# Line 680 | Line 627 | uint8 D64Drive::Write(int channel, uint8
627   *  Execute command string
628   */
629  
630 < void D64Drive::execute_command(char *command)
630 > // BLOCK-READ:channel,0,track,sector
631 > void D64Drive::block_read_cmd(int channel, int track, int sector, bool user_cmd)
632   {
633 <        uint16 adr;
634 <        int len;
635 <
636 <        switch (command[0]) {
637 <                case 'B':
638 <                        if (command[1] != '-')
639 <                                set_error(ERR_SYNTAX30);
640 <                        else
641 <                                switch (command[2]) {
642 <                                        case 'R':
643 <                                                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;
633 >        if (channel >= 16 || chan_mode[channel] != CHMOD_DIRECT) {
634 >                set_error(ERR_NOCHANNEL);
635 >                return;
636 >        }
637 >        read_sector(track, sector, chan_buf[channel]);
638 >        if (user_cmd) {
639 >                buf_len[channel] = 256;
640 >                buf_ptr[channel] = chan_buf[channel];
641 >        } else {
642 >                buf_len[channel] = chan_buf[channel][0];
643 >                buf_ptr[channel] = chan_buf[channel] + 1;
644          }
645   }
646  
647 <
648 < /*
787 < *  Execute B-R command
788 < */
789 <
790 < void D64Drive::block_read_cmd(char *command)
647 > // BUFFER-POINTER:channel,pos
648 > void D64Drive::buffer_pointer_cmd(int channel, int pos)
649   {
650 <        int channel, drvnum, track, sector;
651 <
652 <        if (parse_bcmd(command, &channel, &drvnum, &track, &sector)) {
653 <                if (chan_mode[channel] == CHMOD_DIRECT) {
654 <                        read_sector(track, sector, buf_ptr[channel] = chan_buf[channel]);
655 <                        buf_len[channel] = 256;
798 <                        set_error(ERR_OK);
799 <                } else
800 <                        set_error(ERR_NOCHANNEL);
801 <        } else
802 <                set_error(ERR_SYNTAX30);
650 >        if (channel >= 16 || chan_mode[channel] != CHMOD_DIRECT) {
651 >                set_error(ERR_NOCHANNEL);
652 >                return;
653 >        }
654 >        buf_ptr[channel] = chan_buf[channel] + pos;
655 >        buf_len[channel] = 256 - pos;
656   }
657  
658 <
659 < /*
807 < *  Execute B-P command
808 < */
809 <
810 < void D64Drive::buffer_ptr_cmd(char *command)
658 > // M-R<adr low><adr high>[<number>]
659 > void D64Drive::mem_read_cmd(uint16 adr, uint8 len)
660   {
661 <        int channel, pointer, i;
662 <
663 <        if (parse_bcmd(command, &channel, &pointer, &i, &i)) {
664 <                if (chan_mode[channel] == CHMOD_DIRECT) {
665 <                        buf_ptr[channel] = chan_buf[channel] + pointer;
666 <                        buf_len[channel] = 256 - pointer;
667 <                        set_error(ERR_OK);
668 <                } else
669 <                        set_error(ERR_NOCHANNEL);
821 <        } else
822 <                set_error(ERR_SYNTAX30);
661 >        error_len = len;
662 >        if (adr >= 0x300 && adr < 0x1000) {
663 >                // Read from RAM
664 >                error_ptr = (char *)ram + (adr & 0x7ff);
665 >        } else {
666 >                unsupp_cmd();
667 >                memset(error_buf, 0, len);
668 >                error_ptr = error_buf;
669 >        }
670   }
671  
672 <
673 < /*
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)
672 > // M-W<adr low><adr high><number><data...>
673 > void D64Drive::mem_write_cmd(uint16 adr, uint8 len, uint8 *p)
674   {
675 <        int i;
676 <
677 <        if (*cmd == ':') cmd++;
678 <
679 <        // Read four parameters separated by space, cursor right or comma
680 <        while (*cmd == ' ' || *cmd == 0x1d || *cmd == 0x2c) cmd++;
681 <        if (!*cmd) return false;
682 <
683 <        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;
675 >        while (len) {
676 >                if (adr >= 0x300 && adr < 0x1000) {
677 >                        // Write to RAM
678 >                        ram[adr & 0x7ff] = *p;
679 >                } else if (adr < 0xc000) {
680 >                        unsupp_cmd();
681 >                        return;
682 >                }
683 >                len--; adr++; p++;
684          }
876        *arg4 = i & 0xff;
877
878        return true;
685   }
686  
687 <
688 < /*
883 < *  Execute 'G' command
884 < */
885 <
886 < void D64Drive::chd64_cmd(char *d64name)
687 > // INITIALIZE
688 > void D64Drive::initialize_cmd(void)
689   {
690 <        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 <
690 >        // Close all channels and re-read BAM
691          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
692          read_sector(18, 0, (uint8 *)bam);
693   }
694  
# Line 1021 | Line 810 | int D64Drive::offset_from_ts(int track,
810  
811          return (sector_offset[track] + sector) << 8;
812   }
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 }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines