ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/1541job.cpp
Revision: 1.4
Committed: 2005-06-27T19:55:48Z (18 years, 9 months ago) by cebix
Branch: MAIN
CVS Tags: VERSION_4_2, HEAD
Changes since 1.3: +1 -1 lines
Log Message:
updated copyright dates

File Contents

# Content
1 /*
2 * 1541job.cpp - Emulation of 1541 GCR disk reading/writing
3 *
4 * Frodo (C) 1994-1997,2002-2005 Christian Bauer
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 /*
22 * Notes:
23 * ------
24 *
25 * - This is only used for processor-level 1541 emulation.
26 * It simulates the 1541 disk controller hardware (R/W head,
27 * GCR reading/writing).
28 * - The preferences settings for drive 8 are used to
29 * specify the .d64 file
30 *
31 * Incompatibilities:
32 * ------------------
33 *
34 * - No GCR writing possible (WriteSector is a ROM patch)
35 * - Programs depending on the exact timing of head movement/disk
36 * rotation don't work
37 * - The .d64 error info is unused
38 */
39
40 #include "sysdeps.h"
41
42 #include "1541job.h"
43 #include "CPU1541.h"
44 #include "Prefs.h"
45
46
47 // Number of tracks/sectors
48 const int NUM_TRACKS = 35;
49 const int NUM_SECTORS = 683;
50
51 // Size of GCR encoded data
52 const int GCR_SECTOR_SIZE = 1+10+9+1+325+8; // SYNC Header Gap SYNC Data Gap (should be 5 SYNC bytes each)
53 const int GCR_TRACK_SIZE = GCR_SECTOR_SIZE * 21; // Each track in gcr_data has 21 sectors
54 const int GCR_DISK_SIZE = GCR_TRACK_SIZE * NUM_TRACKS;
55
56 // Job return codes
57 const int RET_OK = 1; // No error
58 const int RET_NOT_FOUND = 2; // Block not found
59 const int RET_NOT_READY = 15; // Drive not ready
60
61
62 // Number of sectors of each track
63 const int num_sectors[36] = {
64 0,
65 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,
66 19,19,19,19,19,19,19,
67 18,18,18,18,18,18,
68 17,17,17,17,17
69 };
70
71 // Sector offset of start of track in .d64 file
72 const int sector_offset[36] = {
73 0,
74 0,21,42,63,84,105,126,147,168,189,210,231,252,273,294,315,336,
75 357,376,395,414,433,452,471,
76 490,508,526,544,562,580,
77 598,615,632,649,666
78 };
79
80
81 /*
82 * Constructor: Open .d64 file if processor-level 1541
83 * emulation is enabled
84 */
85
86 Job1541::Job1541(uint8 *ram1541) : ram(ram1541)
87 {
88 the_file = NULL;
89
90 gcr_data = gcr_ptr = gcr_track_start = new uint8[GCR_DISK_SIZE];
91 gcr_track_end = gcr_track_start + GCR_TRACK_SIZE;
92 current_halftrack = 2;
93
94 disk_changed = true;
95
96 if (ThePrefs.Emul1541Proc)
97 open_d64_file(ThePrefs.DrivePath[0]);
98 }
99
100
101 /*
102 * Destructor: Close .d64 file
103 */
104
105 Job1541::~Job1541()
106 {
107 close_d64_file();
108 delete[] gcr_data;
109 }
110
111
112 /*
113 * Preferences may have changed
114 */
115
116 void Job1541::NewPrefs(Prefs *prefs)
117 {
118 // 1541 emulation turned off?
119 if (!prefs->Emul1541Proc)
120 close_d64_file();
121
122 // 1541 emulation turned on?
123 else if (!ThePrefs.Emul1541Proc && prefs->Emul1541Proc)
124 open_d64_file(prefs->DrivePath[0]);
125
126 // .d64 file name changed?
127 else if (strcmp(ThePrefs.DrivePath[0], prefs->DrivePath[0])) {
128 close_d64_file();
129 open_d64_file(prefs->DrivePath[0]);
130 disk_changed = true;
131 }
132 }
133
134
135 /*
136 * Open .d64 file
137 */
138
139 void Job1541::open_d64_file(char *filepath)
140 {
141 long size;
142 uint8 magic[4];
143 uint8 bam[256];
144
145 // Clear GCR buffer
146 memset(gcr_data, 0x55, GCR_DISK_SIZE);
147
148 // Try opening the file for reading/writing first, then for reading only
149 write_protected = false;
150 the_file = fopen(filepath, "rb+");
151 if (the_file == NULL) {
152 write_protected = true;
153 the_file = fopen(filepath, "rb");
154 }
155 if (the_file != NULL) {
156
157 // Check length
158 fseek(the_file, 0, SEEK_END);
159 if ((size = ftell(the_file)) < NUM_SECTORS * 256) {
160 fclose(the_file);
161 the_file = NULL;
162 return;
163 }
164
165 // x64 image?
166 fseek(the_file, 0, SEEK_SET);
167 fread(&magic, 4, 1, the_file);
168 if (magic[0] == 0x43 && magic[1] == 0x15 && magic[2] == 0x41 && magic[3] == 0x64)
169 image_header = 64;
170 else
171 image_header = 0;
172
173 // Preset error info (all sectors no error)
174 memset(error_info, 1, NUM_SECTORS);
175
176 // Load sector error info from .d64 file, if present
177 if (!image_header && size == NUM_SECTORS * 257) {
178 fseek(the_file, NUM_SECTORS * 256, SEEK_SET);
179 fread(&error_info, NUM_SECTORS, 1, the_file);
180 };
181
182 // Read BAM and get ID
183 read_sector(18, 0, bam);
184 id1 = bam[162];
185 id2 = bam[163];
186
187 // Create GCR encoded disk data from image
188 disk2gcr();
189 }
190 }
191
192
193 /*
194 * Close .d64 file
195 */
196
197 void Job1541::close_d64_file(void)
198 {
199 if (the_file != NULL) {
200 fclose(the_file);
201 the_file = NULL;
202 }
203 }
204
205
206 /*
207 * Write sector to disk (1541 ROM patch)
208 */
209
210 void Job1541::WriteSector(void)
211 {
212 int track = ram[0x18];
213 int sector = ram[0x19];
214 uint16 buf = ram[0x30] | (ram[0x31] << 8);
215
216 if (buf <= 0x0700)
217 if (write_sector(track, sector, ram + buf))
218 sector2gcr(track, sector);
219 }
220
221
222 /*
223 * Format one track (1541 ROM patch)
224 */
225
226 void Job1541::FormatTrack(void)
227 {
228 int track = ram[0x51];
229
230 // Get new ID
231 uint8 bufnum = ram[0x3d];
232 id1 = ram[0x12 + bufnum];
233 id2 = ram[0x13 + bufnum];
234
235 // Create empty block
236 uint8 buf[256];
237 memset(buf, 1, 256);
238 buf[0] = 0x4b;
239
240 // Write block to all sectors on track
241 for(int sector=0; sector<num_sectors[track]; sector++) {
242 write_sector(track, sector, buf);
243 sector2gcr(track, sector);
244 }
245
246 // Clear error info (all sectors no error)
247 if (track == 35)
248 memset(error_info, 1, NUM_SECTORS);
249 // Write error_info to disk?
250 }
251
252
253 /*
254 * Read sector (256 bytes)
255 * true: success, false: error
256 */
257
258 bool Job1541::read_sector(int track, int sector, uint8 *buffer)
259 {
260 int offset;
261
262 // Convert track/sector to byte offset in file
263 if ((offset = offset_from_ts(track, sector)) < 0)
264 return false;
265
266 #ifdef AMIGA
267 if (offset != ftell(the_file))
268 fseek(the_file, offset + image_header, SEEK_SET);
269 #else
270 fseek(the_file, offset + image_header, SEEK_SET);
271 #endif
272 fread(buffer, 256, 1, the_file);
273 return true;
274 }
275
276
277 /*
278 * Write sector (256 bytes) !! -> GCR
279 * true: success, false: error
280 */
281
282 bool Job1541::write_sector(int track, int sector, uint8 *buffer)
283 {
284 int offset;
285
286 // Convert track/sector to byte offset in file
287 if ((offset = offset_from_ts(track, sector)) < 0)
288 return false;
289
290 #ifdef AMIGA
291 if (offset != ftell(the_file))
292 fseek(the_file, offset + image_header, SEEK_SET);
293 #else
294 fseek(the_file, offset + image_header, SEEK_SET);
295 #endif
296 fwrite(buffer, 256, 1, the_file);
297 return true;
298 }
299
300
301 /*
302 * Convert track/sector to offset
303 */
304
305 int Job1541::secnum_from_ts(int track, int sector)
306 {
307 return sector_offset[track] + sector;
308 }
309
310 int Job1541::offset_from_ts(int track, int sector)
311 {
312 if ((track < 1) || (track > NUM_TRACKS) ||
313 (sector < 0) || (sector >= num_sectors[track]))
314 return -1;
315
316 return (sector_offset[track] + sector) << 8;
317 }
318
319
320 /*
321 * Convert 4 bytes to 5 GCR encoded bytes
322 */
323
324 const uint16 gcr_table[16] = {
325 0x0a, 0x0b, 0x12, 0x13, 0x0e, 0x0f, 0x16, 0x17,
326 0x09, 0x19, 0x1a, 0x1b, 0x0d, 0x1d, 0x1e, 0x15
327 };
328
329 void Job1541::gcr_conv4(uint8 *from, uint8 *to)
330 {
331 uint16 g;
332
333 g = (gcr_table[*from >> 4] << 5) | gcr_table[*from & 15];
334 *to++ = g >> 2;
335 *to = (g << 6) & 0xc0;
336 from++;
337
338 g = (gcr_table[*from >> 4] << 5) | gcr_table[*from & 15];
339 *to++ |= (g >> 4) & 0x3f;
340 *to = (g << 4) & 0xf0;
341 from++;
342
343 g = (gcr_table[*from >> 4] << 5) | gcr_table[*from & 15];
344 *to++ |= (g >> 6) & 0x0f;
345 *to = (g << 2) & 0xfc;
346 from++;
347
348 g = (gcr_table[*from >> 4] << 5) | gcr_table[*from & 15];
349 *to++ |= (g >> 8) & 0x03;
350 *to = g;
351 }
352
353
354 /*
355 * Create GCR encoded disk data from image
356 */
357
358 void Job1541::sector2gcr(int track, int sector)
359 {
360 uint8 block[256];
361 uint8 buf[4];
362 uint8 *p = gcr_data + (track-1) * GCR_TRACK_SIZE + sector * GCR_SECTOR_SIZE;
363
364 read_sector(track, sector, block);
365
366 // Create GCR header
367 *p++ = 0xff; // SYNC
368 buf[0] = 0x08; // Header mark
369 buf[1] = sector ^ track ^ id2 ^ id1; // Checksum
370 buf[2] = sector;
371 buf[3] = track;
372 gcr_conv4(buf, p);
373 buf[0] = id2;
374 buf[1] = id1;
375 buf[2] = 0x0f;
376 buf[3] = 0x0f;
377 gcr_conv4(buf, p+5);
378 p += 10;
379 memset(p, 0x55, 9); // Gap
380 p += 9;
381
382 // Create GCR data
383 uint8 sum;
384 *p++ = 0xff; // SYNC
385 buf[0] = 0x07; // Data mark
386 sum = buf[1] = block[0];
387 sum ^= buf[2] = block[1];
388 sum ^= buf[3] = block[2];
389 gcr_conv4(buf, p);
390 p += 5;
391 for (int i=3; i<255; i+=4) {
392 sum ^= buf[0] = block[i];
393 sum ^= buf[1] = block[i+1];
394 sum ^= buf[2] = block[i+2];
395 sum ^= buf[3] = block[i+3];
396 gcr_conv4(buf, p);
397 p += 5;
398 }
399 sum ^= buf[0] = block[255];
400 buf[1] = sum; // Checksum
401 buf[2] = 0;
402 buf[3] = 0;
403 gcr_conv4(buf, p);
404 p += 5;
405 memset(p, 0x55, 8); // Gap
406 }
407
408 void Job1541::disk2gcr(void)
409 {
410 // Convert all tracks and sectors
411 for (int track=1; track<=NUM_TRACKS; track++)
412 for(int sector=0; sector<num_sectors[track]; sector++)
413 sector2gcr(track, sector);
414 }
415
416
417 /*
418 * Move R/W head out (lower track numbers)
419 */
420
421 void Job1541::MoveHeadOut(void)
422 {
423 if (current_halftrack == 2)
424 return;
425 current_halftrack--;
426 #ifndef __riscos__
427 printf("Head move %d\n", current_halftrack);
428 #endif
429 gcr_ptr = gcr_track_start = gcr_data + ((current_halftrack >> 1) - 1) * GCR_TRACK_SIZE;
430 gcr_track_end = gcr_track_start + num_sectors[current_halftrack >> 1] * GCR_SECTOR_SIZE;
431 }
432
433
434 /*
435 * Move R/W head in (higher track numbers)
436 */
437
438 void Job1541::MoveHeadIn(void)
439 {
440 if (current_halftrack == NUM_TRACKS*2)
441 return;
442 current_halftrack++;
443 #ifndef __riscos__
444 printf("Head move %d\n", current_halftrack);
445 #endif
446 gcr_ptr = gcr_track_start = gcr_data + ((current_halftrack >> 1) - 1) * GCR_TRACK_SIZE;
447 gcr_track_end = gcr_track_start + num_sectors[current_halftrack >> 1] * GCR_SECTOR_SIZE;
448 }
449
450
451 /*
452 * Get state
453 */
454
455 void Job1541::GetState(Job1541State *state)
456 {
457 state->current_halftrack = current_halftrack;
458 state->gcr_ptr = gcr_ptr - gcr_data;
459 state->write_protected = write_protected;
460 state->disk_changed = disk_changed;
461 }
462
463
464 /*
465 * Set state
466 */
467
468 void Job1541::SetState(Job1541State *state)
469 {
470 current_halftrack = state->current_halftrack;
471 gcr_ptr = gcr_data + state->gcr_ptr;
472 gcr_track_start = gcr_data + ((current_halftrack >> 1) - 1) * GCR_TRACK_SIZE;
473 gcr_track_end = gcr_track_start + num_sectors[current_halftrack >> 1] * GCR_SECTOR_SIZE;
474 write_protected = state->write_protected;
475 disk_changed = state->disk_changed;
476 }