Main Page | Class Hierarchy | Compound List | File List | Compound Members | File Members | Related Pages

1541d64.cpp

Go to the documentation of this file.
00001 /*
00002  *  1541d64.cpp - 1541 emulation in .d64 file
00003  *
00004  *  Frodo (C) 1994-1997 Christian Bauer
00005  *
00006 
00007  *
00008  * Incompatibilities:
00009  * ------------------
00010  *
00011  *  - Only read accesses possible
00012  *  - Not all commands implemented
00013  *  - The .d64 error info is read, but unused
00014  */
00015 
00016 #include "sysdeps.h"
00017 
00018 #include "1541d64.h"
00019 #include "IEC.h"
00020 #include "Prefs.h"
00021 
00022 
00023 // Channel modes (IRC users listen up :-)
00024 enum {
00025         CHMOD_FREE,                     // Channel free
00026         CHMOD_COMMAND,          // Command/error channel
00027         CHMOD_DIRECTORY,        // Reading directory
00028         CHMOD_FILE,                     // Sequential file open
00029         CHMOD_DIRECT            // Direct buffer access ('#')
00030 };
00031 
00032 // Access modes
00033 enum {
00034         FMODE_READ, FMODE_WRITE, FMODE_APPEND
00035 };
00036 
00037 // File types
00038 enum {
00039         FTYPE_PRG, FTYPE_SEQ, FTYPE_USR, FTYPE_REL
00040 };
00041 
00042 // Number of tracks/sectors
00043 const int NUM_TRACKS = 35;
00044 const int NUM_SECTORS = 683;
00045 
00046 // Prototypes
00047 static bool match(uint8 *p, uint8 *n);
00048 
00049 
00050 /*
00051  *  Constructor: Prepare emulation, open .d64 file
00052  */
00053 
00054 D64Drive::D64Drive(IEC *iec, char *filepath) : Drive(iec)
00055 {
00056         __CHECK_NULL(iec);
00057         __CHECK_NULL(filepath);
00058 
00059         CTOR(D64Drive);
00060 
00061         the_file = NULL;
00062         ram = NULL;
00063 
00064         Ready = false;
00065         strcpy(orig_d64_name, filepath);
00066         for (int i=0; i<=14; i++) {
00067                 chan_mode[i] = CHMOD_FREE;
00068                 chan_buf[i] = NULL;
00069         }
00070         chan_mode[15] = CHMOD_COMMAND;
00071 
00072         // Open .d64 file
00073         open_close_d64_file(filepath);
00074         if (the_file != NULL) {
00075 
00076                 // Allocate 1541 RAM
00077                 ram = new uint8[0x800];
00078                 bam = (BAM *)(ram + 0x700);
00079 
00080                 Reset();
00081                 Ready = true;
00082         }
00083 
00084 }
00085 
00086 
00087 /*
00088  *  Destructor
00089  */
00090 
00091 D64Drive::~D64Drive()
00092 {
00093         // Close .d64 file
00094         open_close_d64_file("");
00095 
00096         delete[] ram;
00097         Ready = false;
00098 
00099         DTOR(D64Drive);
00100 }
00101 
00102 
00103 /*
00104  *  Open/close the .d64 file
00105  */
00106 
00107 void D64Drive::open_close_d64_file(char *d64name)
00108 {
00109         long size;
00110         uint8 magic[4];
00111 
00112         // Close old .d64, if open
00113         if (the_file != NULL) {
00114                 close_all_channels();
00115                 fclose(the_file);
00116                 the_file = NULL;
00117         }
00118 
00119         // Open new .d64 file
00120         if (d64name[0]) {
00121                 if ((the_file = fopen(d64name, "rb")) != NULL) {
00122 
00123                         // Check length
00124                         fseek(the_file, 0, SEEK_END);
00125                         if ((size = ftell(the_file)) < NUM_SECTORS * 256) {
00126                                 fclose(the_file);
00127                                 the_file = NULL;
00128                                 return;
00129                         }
00130 
00131                         // x64 image?
00132                         rewind(the_file);
00133                         fread(&magic, 4, 1, the_file);
00134                         if (magic[0] == 0x43 && magic[1] == 0x15 && magic[2] == 0x41 && magic[3] == 0x64)
00135                                 image_header = 64;
00136                         else
00137                                 image_header = 0;
00138 
00139                         // Preset error info (all sectors no error)
00140                         memset(error_info, 1, NUM_SECTORS);
00141 
00142                         // Load sector error info from .d64 file, if present
00143                         if (!image_header && size == NUM_SECTORS * 257) {
00144                                 fseek(the_file, NUM_SECTORS * 256, SEEK_SET);
00145                                 fread(&error_info, NUM_SECTORS, 1, the_file);
00146                         }
00147                 }
00148         }
00149 }
00150 
00151 
00152 /*
00153  *  Open channel
00154  */
00155 
00156 uint8 D64Drive::Open(int channel, char *filename)
00157 {
00158         set_error(ERR_OK);
00159 
00160         // Channel 15: execute file name as command
00161         if (channel == 15) {
00162                 execute_command(filename);
00163                 return ST_OK;
00164         }
00165 
00166         if (chan_mode[channel] != CHMOD_FREE) {
00167                 set_error(ERR_NOCHANNEL);
00168                 return ST_OK;
00169         }
00170 
00171         if (filename[0] == '$')
00172                 if (channel)
00173                         return open_file_ts(channel, 18, 0);
00174                 else
00175                         return open_directory(filename+1);
00176 
00177         if (filename[0] == '#')
00178                 return open_direct(channel, filename);
00179 
00180         return open_file(channel, filename);
00181 }
00182 
00183 
00184 /*
00185  *  Open file
00186  */
00187 
00188 uint8 D64Drive::open_file(int channel, char *filename)
00189 {
00190         char plainname[256];
00191         int filemode = FMODE_READ;
00192         int filetype = FTYPE_PRG;
00193         int track, sector;
00194 
00195         convert_filename(filename, plainname, &filemode, &filetype);
00196 
00197         // Channel 0 is READ PRG, channel 1 is WRITE PRG
00198         if (!channel) {
00199                 filemode = FMODE_READ;
00200                 filetype = FTYPE_PRG;
00201         }
00202         if (channel == 1) {
00203                 filemode = FMODE_WRITE;
00204                 filetype = FTYPE_PRG;
00205         }
00206 
00207         // Allow only read accesses
00208         if (filemode != FMODE_READ) {
00209                 set_error(ERR_WRITEPROTECT);
00210                 return ST_OK;
00211         }
00212 
00213         // Find file in directory and open it
00214         if (find_file(plainname, &track, &sector))
00215                 return open_file_ts(channel, track, sector);
00216         else
00217                 set_error(ERR_FILENOTFOUND);
00218 
00219         return ST_OK;
00220 }
00221 
00222 
00223 /*
00224  *  Analyze file name, get access mode and type
00225  */
00226 
00227 void D64Drive::convert_filename(char *srcname, char *destname, int *filemode, int *filetype)
00228 {
00229         char *p;
00230 
00231         // Search for ':', p points to first character after ':'
00232         if ((p = strchr(srcname, ':')) != NULL)
00233                 p++;
00234         else
00235                 p = srcname;
00236 
00237         // Remaining string -> destname
00238         strncpy(destname, p, NAMEBUF_LENGTH);
00239 
00240         // Search for ','
00241         p = destname;
00242         while (*p && (*p != ',')) p++;
00243 
00244         // Look for mode parameters seperated by ','
00245         p = destname;
00246         while ((p = strchr(p, ',')) != NULL) {
00247 
00248                 // Cut string after the first ','
00249                 *p++ = 0;
00250 
00251                 switch (*p) {
00252                         case 'P':
00253                                 *filetype = FTYPE_PRG;
00254                                 break;
00255                         case 'S':
00256                                 *filetype = FTYPE_SEQ;
00257                                 break;
00258                         case 'U':
00259                                 *filetype = FTYPE_USR;
00260                                 break;
00261                         case 'L':
00262                                 *filetype = FTYPE_REL;
00263                                 break;
00264                         case 'R':
00265                                 *filemode = FMODE_READ;
00266                                 break;
00267                         case 'W':
00268                                 *filemode = FMODE_WRITE;
00269                                 break;
00270                         case 'A':
00271                                 *filemode = FMODE_APPEND;
00272                                 break;
00273                 }
00274         }
00275 }
00276 
00277 
00278 /*
00279  *  Search file in directory, find first track and sector
00280  *  false: not found, true: found
00281  */
00282 
00283 bool D64Drive::find_file(char *filename, int *track, int *sector)
00284 {
00285         int i, j;
00286         uint8 *p, *q;
00287         DirEntry *de;
00288 
00289         // Scan all directory blocks
00290         dir.next_track = bam->dir_track;
00291         dir.next_sector = bam->dir_sector;
00292 
00293         while (dir.next_track) {
00294                 if (!read_sector(dir.next_track, dir.next_sector, (uint8 *) &dir.next_track))
00295                         return false;
00296 
00297                 // Scan all 8 entries of a block
00298                 for (j=0; j<8; j++) {
00299                         de = &dir.entry[j];
00300                         *track = de->track;
00301                         *sector = de->sector;
00302 
00303                         if (de->type) {
00304                                 p = (uint8 *)filename;
00305                                 q = de->name;
00306                                 for (i=0; i<16 && *p; i++, p++, q++) {
00307                                         if (*p == '*')  // Wildcard '*' matches all following characters
00308                                                 return true;
00309                                         if (*p != *q) {
00310                                                 if (*p != '?') goto next_entry; // Wildcard '?' matches single character
00311                                                 if (*q == 0xa0) goto next_entry;
00312                                         }
00313                                 }
00314 
00315                                 if (i == 16 || *q == 0xa0)
00316                                         return true;
00317                         }
00318 next_entry: ;
00319                 }
00320         }
00321 
00322         return false;
00323 }
00324 
00325 
00326 /*
00327  *  Open file given track/sector of first block
00328  */
00329 
00330 uint8 D64Drive::open_file_ts(int channel, int track, int sector)
00331 {
00332         chan_buf[channel] = new uint8[256];
00333         chan_mode[channel] = CHMOD_FILE;
00334 
00335         // On the next call to Read, the first block will be read
00336         chan_buf[channel][0] = track;
00337         chan_buf[channel][1] = sector;
00338         buf_len[channel] = 0;
00339 
00340         return ST_OK;
00341 }
00342 
00343 
00344 /*
00345  *  Prepare directory as BASIC program (channel 0)
00346  */
00347 
00348 const char type_char_1[] = "DSPUREERSELQGRL?";
00349 const char type_char_2[] = "EERSELQGRL??????";
00350 const char type_char_3[] = "LQGRL???????????";
00351 
00352 // Return true if name 'n' matches pattern 'p'
00353 static bool match(uint8 *p, uint8 *n)
00354 {
00355         if (!*p)                // Null pattern matches everything
00356                 return true;
00357 
00358         do {
00359                 if (*p == '*')  // Wildcard '*' matches all following characters
00360                         return true;
00361                 if ((*p != *n) && (*p != '?'))  // Wildcard '?' matches single character
00362                         return false;
00363                 p++; n++;
00364         } while (*p);
00365 
00366         return *n == 0xa0;
00367 }
00368 
00369 uint8 D64Drive::open_directory(char *pattern)
00370 {
00371         int i, j, n, m;
00372         uint8 *p, *q;
00373         DirEntry *de;
00374         uint8 c;
00375         char *tmppat;
00376 
00377         // Special treatment for "$0"
00378         if (pattern[0] == '0' && pattern[1] == 0)
00379                 pattern += 1;
00380 
00381         // Skip everything before the ':' in the pattern
00382         if ((tmppat = strchr(pattern, ':')) != NULL)
00383                 pattern = tmppat + 1;
00384 
00385         p = buf_ptr[0] = chan_buf[0] = new uint8[8192];
00386         chan_mode[0] = CHMOD_DIRECTORY;
00387 
00388         // Create directory title
00389         *p++ = 0x01;    // Load address $0401 (from PET days :-)
00390         *p++ = 0x04;
00391         *p++ = 0x01;    // Dummy line link
00392         *p++ = 0x01;
00393         *p++ = 0;               // Drive number (0) as line number
00394         *p++ = 0;
00395         *p++ = 0x12;    // RVS ON
00396         *p++ = '\"';
00397 
00398         q = bam->disk_name;
00399         for (i=0; i<23; i++) {
00400                 if ((c = *q++) == 0xa0)
00401                         *p++ = ' ';             // Replace 0xa0 by space
00402                 else
00403                         *p++ = c;
00404         }
00405         *(p-7) = '\"';
00406         *p++ = 0;
00407 
00408         // Scan all directory blocks
00409         dir.next_track = bam->dir_track;
00410         dir.next_sector = bam->dir_sector;
00411 
00412         while (dir.next_track) {
00413                 if (!read_sector(dir.next_track, dir.next_sector, (uint8 *) &dir.next_track))
00414                         return ST_OK;
00415 
00416                 // Scan all 8 entries of a block
00417                 for (j=0; j<8; j++) {
00418                         de = &dir.entry[j];
00419 
00420                         if (de->type && match((uint8 *)pattern, de->name)) {
00421                                 *p++ = 0x01; // Dummy line link
00422                                 *p++ = 0x01;
00423 
00424                                 *p++ = de->num_blocks_l; // Line number
00425                                 *p++ = de->num_blocks_h;
00426 
00427                                 *p++ = ' ';
00428                                 n = (de->num_blocks_h << 8) + de->num_blocks_l;
00429                                 if (n<10) *p++ = ' ';
00430                                 if (n<100) *p++ = ' ';
00431 
00432                                 *p++ = '\"';
00433                                 q = de->name;
00434                                 m = 0;
00435                                 for (i=0; i<16; i++) {
00436                                         if ((c = *q++) == 0xa0) {
00437                                                 if (m)
00438                                                         *p++ = ' ';             // Replace all 0xa0 by spaces
00439                                                 else
00440                                                         m = *p++ = '\"';        // But the first by a '"'
00441                                         } else
00442                                                 *p++ = c;
00443                                 }
00444                                 if (m)
00445                                         *p++ = ' ';
00446                                 else
00447                                         *p++ = '\"';                    // No 0xa0, then append a space
00448 
00449                                 if (de->type & 0x80)
00450                                         *p++ = ' ';
00451                                 else
00452                                         *p++ = '*';
00453 
00454                                 *p++ = type_char_1[de->type & 0x0f];
00455                                 *p++ = type_char_2[de->type & 0x0f];
00456                                 *p++ = type_char_3[de->type & 0x0f];
00457 
00458                                 if (de->type & 0x40)
00459                                         *p++ = '<';
00460                                 else
00461                                         *p++ = ' ';
00462 
00463                                 *p++ = ' ';
00464                                 if (n >= 10) *p++ = ' ';
00465                                 if (n >= 100) *p++ = ' ';
00466                                 *p++ = 0;
00467                         }
00468                 }
00469         }
00470 
00471         // Final line
00472         q = p;
00473         for (i=0; i<29; i++)
00474                 *q++ = ' ';
00475 
00476         n = 0;
00477         for (i=0; i<35; i++)
00478                 n += bam->bitmap[i*4];
00479 
00480         *p++ = 0x01;            // Dummy line link
00481         *p++ = 0x01;
00482         *p++ = n & 0xff;        // Number of free blocks as line number
00483         *p++ = (n >> 8) & 0xff;
00484 
00485         *p++ = 'B';
00486         *p++ = 'L';
00487         *p++ = 'O';
00488         *p++ = 'C';
00489         *p++ = 'K';
00490         *p++ = 'S';
00491         *p++ = ' ';
00492         *p++ = 'F';
00493         *p++ = 'R';
00494         *p++ = 'E';
00495         *p++ = 'E';
00496         *p++ = '.';
00497 
00498         p = q;
00499         *p++ = 0;
00500         *p++ = 0;
00501         *p++ = 0;
00502 
00503         buf_len[0] = p - chan_buf[0];
00504 
00505         return ST_OK;
00506 }
00507 
00508 
00509 /*
00510  *  Open channel for direct buffer access
00511  */
00512 
00513 uint8 D64Drive::open_direct(int channel, char *filename)
00514 {
00515         int buf = -1;
00516 
00517         if (filename[1] == 0)
00518                 buf = alloc_buffer(-1);
00519         else
00520                 if ((filename[1] >= '0') && (filename[1] <= '3') && (filename[2] == 0))
00521                         buf = alloc_buffer(filename[1] - '0');
00522 
00523         if (buf == -1) {
00524                 set_error(ERR_NOCHANNEL);
00525                 return ST_OK;
00526         }
00527 
00528         // The buffers are in the 1541 RAM at $300 and are 256 bytes each
00529         chan_buf[channel] = buf_ptr[channel] = ram + 0x300 + (buf << 8);
00530         chan_mode[channel] = CHMOD_DIRECT;
00531         chan_buf_num[channel] = buf;
00532 
00533         // Store actual buffer number in buffer
00534         *chan_buf[channel] = buf + '0';
00535         buf_len[channel] = 1;
00536 
00537         return ST_OK;
00538 }
00539 
00540 
00541 /*
00542  *  Close channel
00543  */
00544 
00545 uint8 D64Drive::Close(int channel)
00546 {
00547         if (channel == 15) {
00548                 close_all_channels();
00549                 return ST_OK;
00550         }
00551 
00552         switch (chan_mode[channel]) {
00553                 case CHMOD_FREE:
00554                         break;
00555  
00556                 case CHMOD_DIRECT:
00557                         free_buffer(chan_buf_num[channel]);
00558                         chan_buf[channel] = NULL;
00559                         chan_mode[channel] = CHMOD_FREE;
00560                         break;
00561 
00562                 default:
00563                         delete[] chan_buf[channel];
00564                         chan_buf[channel] = NULL;
00565                         chan_mode[channel] = CHMOD_FREE;
00566                         break;
00567         }
00568 
00569         return ST_OK;
00570 }
00571 
00572 
00573 /*
00574  *  Close all channels
00575  */
00576 
00577 void D64Drive::close_all_channels()
00578 {
00579         for (int i=0; i<15; i++)
00580                 Close(i);
00581 
00582         cmd_len = 0;
00583 }
00584 
00585 
00586 /*
00587  *  Read from channel
00588  */
00589 
00590 uint8 D64Drive::Read(int channel, uint8 *byte)
00591 {
00592         switch (chan_mode[channel]) {
00593                 case CHMOD_COMMAND:
00594                         *byte = *error_ptr++;
00595                         if (--error_len)
00596                                 return ST_OK;
00597                         else {
00598                                 set_error(ERR_OK);
00599                                 return ST_EOF;
00600                         }
00601                         break;
00602 
00603                 case CHMOD_FILE:
00604                         // Read next block if necessary
00605                         if (chan_buf[channel][0] && !buf_len[channel]) {
00606                                 if (!read_sector(chan_buf[channel][0], chan_buf[channel][1], chan_buf[channel]))
00607                                         return ST_READ_TIMEOUT;
00608                                 buf_ptr[channel] = chan_buf[channel] + 2;
00609 
00610                                 // Determine block length
00611                                 buf_len[channel] = chan_buf[channel][0] ? 254 : (uint8)chan_buf[channel][1]-1;
00612                         }
00613 
00614                         if (buf_len[channel] > 0) {
00615                                 *byte = *buf_ptr[channel]++;
00616                                 if (!--buf_len[channel] && !chan_buf[channel][0])
00617                                         return ST_EOF;
00618                                 else
00619                                         return ST_OK;
00620                         } else
00621                                 return ST_READ_TIMEOUT;
00622                         break;
00623 
00624                 case CHMOD_DIRECTORY:
00625                 case CHMOD_DIRECT:
00626                         if (buf_len[channel] > 0) {
00627                                 *byte = *buf_ptr[channel]++;
00628                                 if (--buf_len[channel])
00629                                         return ST_OK;
00630                                 else
00631                                         return ST_EOF;
00632                         } else
00633                                 return ST_READ_TIMEOUT;
00634                         break;
00635         }
00636         return ST_READ_TIMEOUT;
00637 }
00638 
00639 
00640 /*
00641  *  Write byte to channel
00642  */
00643 
00644 uint8 D64Drive::Write(int channel, uint8 byte, bool eoi)
00645 {
00646         switch (chan_mode[channel]) {
00647                 case CHMOD_FREE:
00648                         set_error(ERR_FILENOTOPEN);
00649                         break;
00650 
00651                 case CHMOD_COMMAND:
00652                         // Collect characters and execute command on EOI
00653                         if (cmd_len >= 40)
00654                                 return ST_TIMEOUT;
00655 
00656                         cmd_buffer[cmd_len++] = byte;
00657 
00658                         if (eoi) {
00659                                 cmd_buffer[cmd_len++] = 0;
00660                                 cmd_len = 0;
00661                                 execute_command(cmd_buffer);
00662                         }
00663                         return ST_OK;
00664 
00665                 case CHMOD_DIRECTORY:
00666                         set_error(ERR_WRITEFILEOPEN);
00667                         break;
00668         }
00669         return ST_TIMEOUT;
00670 }
00671 
00672 
00673 /*
00674  *  Execute command string
00675  */
00676 
00677 void D64Drive::execute_command(char *command)
00678 {
00679         uint16 adr;
00680         int len;
00681 
00682         switch (command[0]) {
00683                 case 'B':
00684                         if (command[1] != '-')
00685                                 set_error(ERR_SYNTAX30);
00686                         else
00687                                 switch (command[2]) {
00688                                         case 'R':
00689                                                 block_read_cmd(&command[3]);
00690                                                 break;
00691 
00692                                         case 'P':
00693                                                 buffer_ptr_cmd(&command[3]);
00694                                                 break;
00695 
00696                                         case 'A':
00697                                         case 'F':
00698                                         case 'W':
00699                                                 set_error(ERR_WRITEPROTECT);
00700                                                 break;
00701 
00702                                         default:
00703                                                 set_error(ERR_SYNTAX30);
00704                                                 break;
00705                                 }
00706                         break;
00707 
00708                 case 'M':
00709                         if (command[1] != '-')
00710                                 set_error(ERR_SYNTAX30);
00711                         else
00712                                 switch (command[2]) {
00713                                         case 'R':
00714                                                 adr = ((uint8)command[4] << 8) | ((uint8)command[3]);
00715                                                 error_ptr = (char *)(ram + (adr & 0x07ff));
00716                                                 if (!(error_len = (uint8)command[5]))
00717                                                         error_len = 1;
00718                                                 break;
00719 
00720                                         case 'W':
00721                                                 {
00722                                                 adr = ((uint8)command[4] << 8) | ((uint8)command[3]);
00723                                                 len = (uint8)command[5];
00724                                                 for (int i=0; i<len; i++)
00725                                                         ram[adr+i] = (uint8)command[i+6];
00726                                                 }
00727                                                 break;
00728 
00729                                         default:
00730                                                 set_error(ERR_SYNTAX30);
00731                                 }
00732                         break;
00733 
00734                 case 'I':
00735                         close_all_channels();
00736                         read_sector(18, 0, (uint8 *)bam);
00737                         set_error(ERR_OK);
00738                         break;
00739 
00740                 case 'U':
00741                         switch (command[1] & 0x0f) {
00742                                 case 1:         // U1/UA: Block-Read
00743                                         block_read_cmd(&command[2]);
00744                                         break;
00745 
00746                                 case 2:         // U2/UB: Block-Write
00747                                         set_error(ERR_WRITEPROTECT);
00748                                         break;
00749 
00750                                 case 10:        // U:/UJ: Reset
00751                                         Reset();
00752                                         break;
00753 
00754                                 default:
00755                                         set_error(ERR_SYNTAX30);
00756                                         break;
00757                         }
00758                         break;
00759 
00760                 case 'G':
00761                         if (command[1] != ':')
00762                                 set_error(ERR_SYNTAX30);
00763                         else
00764                                 chd64_cmd(&command[2]);
00765                         break;
00766 
00767                 case 'C':
00768                 case 'N':
00769                 case 'R':
00770                 case 'S':
00771                 case 'V':
00772                         set_error(ERR_WRITEPROTECT);
00773                         break;
00774 
00775                 default:
00776                         set_error(ERR_SYNTAX30);
00777                         break;
00778         }
00779 }
00780 
00781 
00782 /*
00783  *  Execute B-R command
00784  */
00785 
00786 void D64Drive::block_read_cmd(char *command)
00787 {
00788         int channel, drvnum, track, sector;
00789 
00790         if (parse_bcmd(command, &channel, &drvnum, &track, &sector)) {
00791                 if (chan_mode[channel] == CHMOD_DIRECT) {
00792                         read_sector(track, sector, buf_ptr[channel] = chan_buf[channel]);
00793                         buf_len[channel] = 256;
00794                         set_error(ERR_OK);
00795                 } else
00796                         set_error(ERR_NOCHANNEL);
00797         } else
00798                 set_error(ERR_SYNTAX30);
00799 }
00800 
00801 
00802 /*
00803  *  Execute B-P command
00804  */
00805 
00806 void D64Drive::buffer_ptr_cmd(char *command)
00807 {
00808         int channel, pointer, i;
00809 
00810         if (parse_bcmd(command, &channel, &pointer, &i, &i)) {
00811                 if (chan_mode[channel] == CHMOD_DIRECT) {
00812                         buf_ptr[channel] = chan_buf[channel] + pointer;
00813                         buf_len[channel] = 256 - pointer;
00814                         set_error(ERR_OK);
00815                 } else
00816                         set_error(ERR_NOCHANNEL);
00817         } else
00818                 set_error(ERR_SYNTAX30);
00819 }
00820 
00821 
00822 /*
00823  *  Parse block command parameters
00824  *  true: OK, false: error
00825  */
00826 
00827 bool D64Drive::parse_bcmd(char *cmd, int *arg1, int *arg2, int *arg3, int *arg4)
00828 {
00829         int i;
00830 
00831         if (*cmd == ':') cmd++;
00832 
00833         // Read four parameters separated by space, cursor right or comma
00834         while (*cmd == ' ' || *cmd == 0x1d || *cmd == 0x2c) cmd++;
00835         if (!*cmd) return false;
00836 
00837         i = 0;
00838         while (*cmd >= 0x30 && *cmd < 0x40) {
00839                 i *= 10;
00840                 i += *cmd++ & 0x0f;
00841         }
00842         *arg1 = i & 0xff;
00843 
00844         while (*cmd == ' ' || *cmd == 0x1d || *cmd == 0x2c) cmd++;
00845         if (!*cmd) return false;
00846 
00847         i = 0;
00848         while (*cmd >= 0x30 && *cmd < 0x40) {
00849                 i *= 10;
00850                 i += *cmd++ & 0x0f;
00851         }
00852         *arg2 = i & 0xff;
00853 
00854         while (*cmd == ' ' || *cmd == 0x1d || *cmd == 0x2c) cmd++;
00855         if (!*cmd) return false;
00856 
00857         i = 0;
00858         while (*cmd >= 0x30 && *cmd < 0x40) {
00859                 i *= 10;
00860                 i += *cmd++ & 0x0f;
00861         }
00862         *arg3 = i & 0xff;
00863 
00864         while (*cmd == ' ' || *cmd == 0x1d || *cmd == 0x2c) cmd++;
00865         if (!*cmd) return false;
00866 
00867         i = 0;
00868         while (*cmd >= 0x30 && *cmd < 0x40) {
00869                 i *= 10;
00870                 i += *cmd++ & 0x0f;
00871         }
00872         *arg4 = i & 0xff;
00873 
00874         return true;
00875 }
00876 
00877 
00878 /*
00879  *  Execute 'G' command
00880  */
00881 
00882 void D64Drive::chd64_cmd(char *d64name)
00883 {
00884         char str[NAMEBUF_LENGTH];
00885         char *p = str;
00886 
00887         // Convert .d64 file name
00888         for (int i=0; i<NAMEBUF_LENGTH && (*p++ = conv_from_64(*d64name++, false)); i++) ;
00889 
00890         close_all_channels();
00891 
00892         // G:. resets the .d64 file name to its original setting
00893         if (str[0] == '.' && str[1] == 0)
00894                 open_close_d64_file(orig_d64_name);
00895         else
00896                 open_close_d64_file(str);
00897 
00898         // Read BAM
00899         read_sector(18, 0, (uint8 *)bam);
00900 }
00901 
00902 
00903 /*
00904  *  Reset drive
00905  */
00906 
00907 void D64Drive::Reset(void)
00908 {
00909         close_all_channels();
00910 
00911         read_sector(18, 0, (uint8 *)bam);
00912 
00913         cmd_len = 0;
00914         for (int i=0; i<4; i++)
00915                 buf_free[i] = true;
00916 
00917         set_error(ERR_STARTUP);
00918 
00919         ELOG1(_L8("D64 drive reset\n"));
00920 }
00921 
00922 
00923 /*
00924  *  Allocate floppy buffer
00925  *   -> Desired buffer number or -1
00926  *   <- Allocated buffer number or -1
00927  */
00928 
00929 int D64Drive::alloc_buffer(int want)
00930 {
00931         if (want == -1) {
00932                 for (want=3; want>=0; want--)
00933                         if (buf_free[want]) {
00934                                 buf_free[want] = false;
00935                                 return want;
00936                         }
00937                 return -1;
00938         }
00939 
00940         if (want < 4)
00941                 if (buf_free[want]) {
00942                         buf_free[want] = false;
00943                         return want;
00944                 } else
00945                         return -1;
00946         else
00947                 return -1;
00948 }
00949 
00950 
00951 /*
00952  *  Free floppy buffer
00953  */
00954 
00955 void D64Drive::free_buffer(int buf)
00956 {
00957         buf_free[buf] = true;
00958 }
00959 
00960 
00961 /*
00962  *  Read sector (256 bytes)
00963  *  true: success, false: error
00964  */
00965 
00966 bool D64Drive::read_sector(int track, int sector, uint8 *buffer)
00967 {
00968         int offset;
00969 
00970         // Convert track/sector to byte offset in file
00971         if ((offset = offset_from_ts(track, sector)) < 0) {
00972                 set_error(ERR_ILLEGALTS);
00973                 return false;
00974         }
00975 
00976         if (the_file == NULL) {
00977                 set_error(ERR_NOTREADY);
00978                 return false;
00979         }
00980 
00981 #ifdef AMIGA
00982         if (offset != ftell(the_file))
00983                 fseek(the_file, offset + image_header, SEEK_SET);
00984 #else
00985         fseek(the_file, offset + image_header, SEEK_SET);
00986 #endif
00987         fread(buffer, 256, 1, the_file);
00988         return true;
00989 }
00990 
00991 
00992 /*
00993  *  Convert track/sector to offset
00994  */
00995 
00996 const int num_sectors[41] = {
00997         0,
00998         21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,
00999         19,19,19,19,19,19,19,
01000         18,18,18,18,18,18,
01001         17,17,17,17,17,
01002         17,17,17,17,17          // Tracks 36..40
01003 };
01004 
01005 const int sector_offset[41] = {
01006         0,
01007         0,21,42,63,84,105,126,147,168,189,210,231,252,273,294,315,336,
01008         357,376,395,414,433,452,471,
01009         490,508,526,544,562,580,
01010         598,615,632,649,666,
01011         683,700,717,734,751     // Tracks 36..40
01012 };
01013 
01014 int D64Drive::offset_from_ts(int track, int sector)
01015 {
01016         if ((track < 1) || (track > NUM_TRACKS) ||
01017                 (sector < 0) || (sector >= num_sectors[track]))
01018                 return -1;
01019 
01020         return (sector_offset[track] + sector) << 8;
01021 }
01022 
01023 
01024 /*
01025  *  Conversion PETSCII->ASCII
01026  */
01027 
01028 uint8 D64Drive::conv_from_64(uint8 c, bool map_slash)
01029 {
01030         if ((c >= 'A') && (c <= 'Z') || (c >= 'a') && (c <= 'z'))
01031                 return c ^ 0x20;
01032         if ((c >= 0xc1) && (c <= 0xda))
01033                 return c ^ 0x80;
01034         if ((c == '/') && map_slash) 
01035                 return '\\';
01036         return c;
01037 }

Generated on Tue Feb 8 04:07:11 2005 for E32frodo by doxygen 1.3.3