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

1541job.cpp

Go to the documentation of this file.
00001 /*
00002  *  1541job.cpp - Emulation of 1541 GCR disk reading/writing
00003  *
00004  *  Frodo (C) 1994-1997 Christian Bauer
00005  *
00006 
00007  *
00008  * Notes:
00009  * ------
00010  *
00011  *  - This is only used for processor-level 1541 emulation.
00012  *    It simulates the 1541 disk controller hardware (R/W head,
00013  *    GCR reading/writing).
00014  *  - The preferences settings for drive 8 are used to
00015  *    specify the .d64 file
00016  *
00017  * Incompatibilities:
00018  * ------------------
00019  *
00020  *  - No GCR writing possible (WriteSector is a ROM patch)
00021  *  - Programs depending on the exact timing of head movement/disk
00022  *    rotation don't work
00023  *  - The .d64 error info is unused
00024  */
00025 
00026 #include "sysdeps.h"
00027 
00028 #include "1541job.h"
00029 #include "CPU1541.h"
00030 #include "Prefs.h"
00031 
00032 
00033 // Number of tracks/sectors
00034 const int NUM_TRACKS = 35;
00035 const int NUM_SECTORS = 683;
00036 
00037 // Size of GCR encoded data
00038 const int GCR_SECTOR_SIZE = 1+10+9+1+325+8;                     // SYNC Header Gap SYNC Data Gap (should be 5 SYNC bytes each)
00039 const int GCR_TRACK_SIZE = GCR_SECTOR_SIZE * 21;        // Each track in gcr_data has 21 sectors
00040 const int GCR_DISK_SIZE = GCR_TRACK_SIZE * NUM_TRACKS;
00041 
00042 // Job return codes
00043 const int RET_OK = 1;                           // No error
00044 const int RET_NOT_FOUND = 2;            // Block not found
00045 const int RET_NOT_READY = 15;           // Drive not ready
00046 
00047 
00048 // Number of sectors of each track
00049 const int num_sectors[36] = {
00050         0,
00051         21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,
00052         19,19,19,19,19,19,19,
00053         18,18,18,18,18,18,
00054         17,17,17,17,17
00055 };
00056 
00057 // Sector offset of start of track in .d64 file
00058 const int sector_offset[36] = {
00059         0,
00060         0,21,42,63,84,105,126,147,168,189,210,231,252,273,294,315,336,
00061         357,376,395,414,433,452,471,
00062         490,508,526,544,562,580,
00063         598,615,632,649,666
00064 };
00065 
00066 
00067 /*
00068  *  Constructor: Open .d64 file if processor-level 1541
00069  *   emulation is enabled
00070  */
00071 
00072 Job1541::Job1541(uint8 *ram1541, C64* c64) : ram(ram1541), ThePrefs(c64->ThePrefs)
00073 {
00074         __CHECK_NULL(ram1541);
00075         __CHECK_NULL(c64);
00076 
00077         the_file = NULL;
00078 
00079         gcr_data = gcr_ptr = gcr_track_start = new uint8[GCR_DISK_SIZE];
00080         gcr_track_end = gcr_track_start + GCR_TRACK_SIZE;
00081         current_halftrack = 2;
00082 
00083         disk_changed = true;
00084 
00085         if (ThePrefs.Emul1541Proc)
00086                 open_d64_file(ThePrefs.DrivePath[0]);
00087 
00088         CTOR(Job1541);
00089 }
00090 
00091 
00092 /*
00093  *  Destructor: Close .d64 file
00094  */
00095 
00096 Job1541::~Job1541()
00097 {
00098         close_d64_file();
00099         delete[] gcr_data;
00100 
00101         DTOR(Job1541);
00102 }
00103 
00104 
00105 /*
00106  *  Preferences may have changed
00107  */
00108 
00109 void Job1541::NewPrefs(Prefs *prefs)
00110 {
00111         // 1541 emulation turned off?
00112         if (!prefs->Emul1541Proc)
00113                 close_d64_file();
00114 
00115         // 1541 emulation turned on?
00116         else if (!ThePrefs.Emul1541Proc && prefs->Emul1541Proc)
00117                 open_d64_file(prefs->DrivePath[0]);
00118 
00119         // .d64 file name changed?
00120         else if (strcmp(ThePrefs.DrivePath[0], prefs->DrivePath[0])) {
00121                 close_d64_file();
00122                 open_d64_file(prefs->DrivePath[0]);
00123                 disk_changed = true;
00124         }
00125 }
00126 
00127 
00128 /*
00129  *  Open .d64 file
00130  */
00131 
00132 void Job1541::open_d64_file(char *filepath)
00133 {
00134         long size;
00135         uint8 magic[4];
00136         uint8 bam[256];
00137 
00138         // Clear GCR buffer
00139         memset(gcr_data, 0x55, GCR_DISK_SIZE);
00140 
00141         // Try opening the file for reading/writing first, then for reading only
00142         write_protected = false;
00143         the_file = fopen(filepath, "rb+");
00144         if (the_file == NULL) {
00145                 write_protected = true;
00146                 the_file = fopen(filepath, "rb");
00147         }
00148         if (the_file != NULL) {
00149 
00150                 // Check length
00151                 fseek(the_file, 0, SEEK_END);
00152                 if ((size = ftell(the_file)) < NUM_SECTORS * 256) {
00153                         fclose(the_file);
00154                         the_file = NULL;
00155                         return;
00156                 }
00157 
00158                 // x64 image?
00159                 fseek(the_file, 0, SEEK_SET);
00160                 fread(&magic, 4, 1, the_file);
00161                 if (magic[0] == 0x43 && magic[1] == 0x15 && magic[2] == 0x41 && magic[3] == 0x64)
00162                         image_header = 64;
00163                 else
00164                         image_header = 0;
00165 
00166                 // Preset error info (all sectors no error)
00167                 memset(error_info, 1, NUM_SECTORS);
00168 
00169                 // Load sector error info from .d64 file, if present
00170                 if (!image_header && size == NUM_SECTORS * 257) {
00171                         fseek(the_file, NUM_SECTORS * 256, SEEK_SET);
00172                         fread(&error_info, NUM_SECTORS, 1, the_file);
00173                 };
00174 
00175                 // Read BAM and get ID
00176                 read_sector(18, 0, bam);
00177                 id1 = bam[162];
00178                 id2 = bam[163];
00179 
00180                 // Create GCR encoded disk data from image
00181                 disk2gcr();
00182         }
00183 }
00184 
00185 
00186 /*
00187  *  Close .d64 file
00188  */
00189 
00190 void Job1541::close_d64_file(void)
00191 {
00192         if (the_file != NULL) {
00193                 fclose(the_file);
00194                 the_file = NULL;
00195         }
00196 }
00197 
00198 
00199 /*
00200  *  Write sector to disk (1541 ROM patch)
00201  */
00202 
00203 void Job1541::WriteSector(void)
00204 {
00205         int track = ram[0x18];
00206         int sector = ram[0x19];
00207         uint16 buf = ram[0x30] | (ram[0x31] << 8);
00208 
00209         if (buf <= 0x0700)
00210                 if (write_sector(track, sector, ram + buf))
00211                         sector2gcr(track, sector);
00212 }
00213 
00214 
00215 /*
00216  *  Format one track (1541 ROM patch)
00217  */
00218 
00219 void Job1541::FormatTrack(void)
00220 {
00221         int track = ram[0x51];
00222 
00223         // Get new ID
00224         uint8 bufnum = ram[0x3d];
00225         id1 = ram[0x12 + bufnum];
00226         id2 = ram[0x13 + bufnum];
00227 
00228         // Create empty block
00229         uint8 buf[256];
00230         memset(buf, 1, 256);
00231         buf[0] = 0x4b;
00232 
00233         // Write block to all sectors on track
00234         for(int sector=0; sector<num_sectors[track]; sector++) {
00235                 write_sector(track, sector, buf);
00236                 sector2gcr(track, sector);
00237         }
00238 
00239         // Clear error info (all sectors no error)
00240         if (track == 35)
00241                 memset(error_info, 1, NUM_SECTORS);
00242                 // Write error_info to disk?
00243 }
00244 
00245 
00246 /*
00247  *  Read sector (256 bytes)
00248  *  true: success, false: error
00249  */
00250 
00251 bool Job1541::read_sector(int track, int sector, uint8 *buffer)
00252 {
00253         int offset;
00254 
00255         // Convert track/sector to byte offset in file
00256         if ((offset = offset_from_ts(track, sector)) < 0)
00257                 return false;
00258 
00259 #ifdef AMIGA
00260         if (offset != ftell(the_file))
00261                 fseek(the_file, offset + image_header, SEEK_SET);
00262 #else
00263         fseek(the_file, offset + image_header, SEEK_SET);
00264 #endif
00265         fread(buffer, 256, 1, the_file);
00266         return true;
00267 }
00268 
00269 
00270 /*
00271  *  Write sector (256 bytes) !! -> GCR
00272  *  true: success, false: error
00273  */
00274 
00275 bool Job1541::write_sector(int track, int sector, uint8 *buffer)
00276 {
00277         int offset;
00278 
00279         // Convert track/sector to byte offset in file
00280         if ((offset = offset_from_ts(track, sector)) < 0)
00281                 return false;
00282 
00283 #ifdef AMIGA
00284         if (offset != ftell(the_file))
00285                 fseek(the_file, offset + image_header, SEEK_SET);
00286 #else
00287         fseek(the_file, offset + image_header, SEEK_SET);
00288 #endif
00289         fwrite(buffer, 256, 1, the_file);
00290         return true;
00291 }
00292 
00293 
00294 /*
00295  *  Convert track/sector to offset
00296  */
00297 
00298 int Job1541::secnum_from_ts(int track, int sector)
00299 {
00300         return sector_offset[track] + sector;
00301 }
00302 
00303 int Job1541::offset_from_ts(int track, int sector)
00304 {
00305         if ((track < 1) || (track > NUM_TRACKS) ||
00306                 (sector < 0) || (sector >= num_sectors[track]))
00307                 return -1;
00308 
00309         return (sector_offset[track] + sector) << 8;
00310 }
00311 
00312 
00313 /*
00314  *  Convert 4 bytes to 5 GCR encoded bytes
00315  */
00316 
00317 const uint16 gcr_table[16] = {
00318         0x0a, 0x0b, 0x12, 0x13, 0x0e, 0x0f, 0x16, 0x17,
00319         0x09, 0x19, 0x1a, 0x1b, 0x0d, 0x1d, 0x1e, 0x15
00320 };
00321 
00322 void Job1541::gcr_conv4(uint8 *from, uint8 *to)
00323 {
00324         uint16 g;
00325 
00326         g = (gcr_table[*from >> 4] << 5) | gcr_table[*from & 15];
00327         *to++ = g >> 2;
00328         *to = (g << 6) & 0xc0;
00329         from++;
00330 
00331         g = (gcr_table[*from >> 4] << 5) | gcr_table[*from & 15];
00332         *to++ |= (g >> 4) & 0x3f;
00333         *to = (g << 4) & 0xf0;
00334         from++;
00335 
00336         g = (gcr_table[*from >> 4] << 5) | gcr_table[*from & 15];
00337         *to++ |= (g >> 6) & 0x0f;
00338         *to = (g << 2) & 0xfc;
00339         from++;
00340 
00341         g = (gcr_table[*from >> 4] << 5) | gcr_table[*from & 15];
00342         *to++ |= (g >> 8) & 0x03;
00343         *to = g;
00344 }
00345 
00346 
00347 /*
00348  *  Create GCR encoded disk data from image
00349  */
00350 
00351 void Job1541::sector2gcr(int track, int sector)
00352 {
00353         uint8 block[256];
00354         uint8 buf[4];
00355         uint8 *p = gcr_data + (track-1) * GCR_TRACK_SIZE + sector * GCR_SECTOR_SIZE;
00356 
00357         read_sector(track, sector, block);
00358 
00359         // Create GCR header
00360         *p++ = 0xff;                                                    // SYNC
00361         buf[0] = 0x08;                                                  // Header mark
00362         buf[1] = sector ^ track ^ id2 ^ id1;    // Checksum
00363         buf[2] = sector;
00364         buf[3] = track;
00365         gcr_conv4(buf, p);
00366         buf[0] = id2;
00367         buf[1] = id1;
00368         buf[2] = 0x0f;
00369         buf[3] = 0x0f;
00370         gcr_conv4(buf, p+5);
00371         p += 10;
00372         memset(p, 0x55, 9);                                             // Gap
00373         p += 9;
00374 
00375         // Create GCR data
00376         uint8 sum;
00377         *p++ = 0xff;                                                    // SYNC
00378         buf[0] = 0x07;                                                  // Data mark
00379         sum = buf[1] = block[0];
00380         sum ^= buf[2] = block[1];
00381         sum ^= buf[3] = block[2];
00382         gcr_conv4(buf, p);
00383         p += 5;
00384         for (int i=3; i<255; i+=4) {
00385                 sum ^= buf[0] = block[i];
00386                 sum ^= buf[1] = block[i+1];
00387                 sum ^= buf[2] = block[i+2];
00388                 sum ^= buf[3] = block[i+3];
00389                 gcr_conv4(buf, p);
00390                 p += 5;
00391         }
00392         sum ^= buf[0] = block[255];
00393         buf[1] = sum;                                                   // Checksum
00394         buf[2] = 0;
00395         buf[3] = 0;
00396         gcr_conv4(buf, p);
00397         p += 5;
00398         memset(p, 0x55, 8);                                             // Gap
00399 }
00400 
00401 void Job1541::disk2gcr(void)
00402 {
00403         // Convert all tracks and sectors
00404         for (int track=1; track<=NUM_TRACKS; track++)
00405                 for(int sector=0; sector<num_sectors[track]; sector++)
00406                         sector2gcr(track, sector);
00407 }
00408 
00409 
00410 /*
00411  *  Move R/W head out (lower track numbers)
00412  */
00413 
00414 void Job1541::MoveHeadOut(void)
00415 {
00416         if (current_halftrack == 2)
00417                 return;
00418         current_halftrack--;
00419 #if !defined(__riscos__) && !defined(__SYMBIAN32__)
00420         printf("Head move %d\n", current_halftrack);
00421 #endif
00422         gcr_ptr = gcr_track_start = gcr_data + ((current_halftrack >> 1) - 1) * GCR_TRACK_SIZE;
00423         gcr_track_end = gcr_track_start + num_sectors[current_halftrack >> 1] * GCR_SECTOR_SIZE;
00424 }
00425 
00426 
00427 /*
00428  *  Move R/W head in (higher track numbers)
00429  */
00430 
00431 void Job1541::MoveHeadIn(void)
00432 {
00433         if (current_halftrack == NUM_TRACKS*2)
00434                 return;
00435         current_halftrack++;
00436 #if !defined(__riscos__) && !defined(__SYMBIAN32__)
00437         printf("Head move %d\n", current_halftrack);
00438 #endif
00439         gcr_ptr = gcr_track_start = gcr_data + ((current_halftrack >> 1) - 1) * GCR_TRACK_SIZE;
00440         gcr_track_end = gcr_track_start + num_sectors[current_halftrack >> 1] * GCR_SECTOR_SIZE;
00441 }
00442 
00443 
00444 /*
00445  *  Get state
00446  */
00447 
00448 void Job1541::GetState(Job1541State *state)
00449 {
00450         state->current_halftrack = current_halftrack;
00451         state->gcr_ptr = gcr_ptr - gcr_data;
00452         state->write_protected = write_protected;
00453         state->disk_changed = disk_changed;
00454 }
00455 
00456 
00457 /*
00458  *  Set state
00459  */
00460 
00461 void Job1541::SetState(Job1541State *state)
00462 {
00463         current_halftrack = state->current_halftrack;
00464         gcr_ptr = gcr_data + state->gcr_ptr;
00465         gcr_track_start = gcr_data + ((current_halftrack >> 1) - 1) * GCR_TRACK_SIZE;
00466         gcr_track_end = gcr_track_start + num_sectors[current_halftrack >> 1] * GCR_SECTOR_SIZE;
00467         write_protected = state->write_protected;
00468         disk_changed = state->disk_changed;
00469 }

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