1 /*
2 * drive.c - Hardware-level disk drive emulation.
3 *
4 * Written by
5 * Andreas Boose <viceteam@t-online.de>
6 *
7 * Based on old code by
8 * Daniel Sladic <sladic@eecg.toronto.edu>
9 * Ettore Perazzoli <ettore@comm2000.it>
10 * Andre Fachat <fachat@physik.tu-chemnitz.de>
11 * Teemu Rantanen <tvr@cs.hut.fi>
12 *
13 * This file is part of VICE, the Versatile Commodore Emulator.
14 * See README for copyright notice.
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
29 * 02111-1307 USA.
30 *
31 */
32
33 /* TODO:
34 - more accurate emulation of disk rotation.
35 - different speeds within one track.
36 - check for byte ready *within* `BVC', `BVS' and `PHP'.
37 - serial bus handling might be faster. */
38
39 #include "vice.h"
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <math.h>
45 #include <assert.h>
46
47 #include "attach.h"
48 #include "diskconstants.h"
49 #include "diskimage.h"
50 #include "drive-check.h"
51 #include "drive-overflow.h"
52 #include "drive.h"
53 #include "drivecpu.h"
54 #include "drivecpu65c02.h"
55 #include "driveimage.h"
56 #include "drivesync.h"
57 #include "driverom.h"
58 #include "drivetypes.h"
59 #include "gcr.h"
60 #include "iecbus.h"
61 #include "iecdrive.h"
62 #include "lib.h"
63 #include "log.h"
64 #include "machine-drive.h"
65 #include "machine.h"
66 #include "maincpu.h"
67 #include "resources.h"
68 #include "rotation.h"
69 #include "types.h"
70 #include "uiapi.h"
71 #include "ds1216e.h"
72 #include "drive-sound.h"
73 #include "p64.h"
74 #include "monitor.h"
75
76 static int drive_init_was_called = 0;
77
78 drive_context_t *drive_context[DRIVE_NUM];
79
80 /* Generic drive logging goes here. */
81 static log_t drive_log = LOG_ERR;
82
83 /* If nonzero, at least one vaild drive ROM has already been loaded. */
84 int rom_loaded = 0;
85
86 /* ------------------------------------------------------------------------- */
87
88 static int drive_led_color[DRIVE_NUM];
89
90 /* ------------------------------------------------------------------------- */
91
drive_set_disk_memory(uint8_t * id,unsigned int track,unsigned int sector,struct drive_context_s * drv)92 void drive_set_disk_memory(uint8_t *id, unsigned int track, unsigned int sector,
93 struct drive_context_s *drv)
94 {
95 drive_t *drive;
96
97 drive = drv->drive;
98
99 if (drive->type == DRIVE_TYPE_1540
100 || drive->type == DRIVE_TYPE_1541
101 || drive->type == DRIVE_TYPE_1541II
102 || drive->type == DRIVE_TYPE_1570
103 || drive->type == DRIVE_TYPE_1571
104 || drive->type == DRIVE_TYPE_1571CR) {
105 drv->drive->drive_ram[0x12] = id[0];
106 drv->drive->drive_ram[0x13] = id[1];
107 drv->drive->drive_ram[0x16] = id[0];
108 drv->drive->drive_ram[0x17] = id[1];
109 drv->drive->drive_ram[0x18] = track;
110 drv->drive->drive_ram[0x19] = sector;
111 drv->drive->drive_ram[0x22] = track;
112 }
113 }
114
drive_set_last_read(unsigned int track,unsigned int sector,uint8_t * buffer,struct drive_context_s * drv)115 void drive_set_last_read(unsigned int track, unsigned int sector, uint8_t *buffer,
116 struct drive_context_s *drv)
117 {
118 drive_t *drive;
119 int side = 0;
120
121 drive = drv->drive;
122
123 drive_gcr_data_writeback(drive);
124
125 if (drive->type == DRIVE_TYPE_1570
126 || drive->type == DRIVE_TYPE_1571
127 || drive->type == DRIVE_TYPE_1571CR) {
128 if (track > (DRIVE_HALFTRACKS_1571 / 2)) {
129 track -= (DRIVE_HALFTRACKS_1571 / 2);
130 side = 1;
131 }
132 }
133 drive_set_half_track(track * 2, side, drive);
134
135 if (drive->type == DRIVE_TYPE_1540
136 || drive->type == DRIVE_TYPE_1541
137 || drive->type == DRIVE_TYPE_1541II
138 || drive->type == DRIVE_TYPE_1570
139 || drive->type == DRIVE_TYPE_1571
140 || drive->type == DRIVE_TYPE_1571CR) {
141 memcpy(&(drv->drive->drive_ram[0x0400]), buffer, 256);
142 }
143 }
144
145 /* ------------------------------------------------------------------------- */
146
147 /* Initialize the hardware-level drive emulation (should be called at least
148 once before anything else). Return 0 on success, -1 on error. */
drive_init(void)149 int drive_init(void)
150 {
151 unsigned int dnr;
152 drive_t *drive;
153
154 if (rom_loaded) {
155 return 0;
156 }
157
158 drive_init_was_called = 1;
159
160 driverom_init();
161 drive_image_init();
162
163 drive_log = log_open("Drive");
164
165 for (dnr = 0; dnr < DRIVE_NUM; dnr++) {
166 char *logname;
167
168 drive = drive_context[dnr]->drive;
169 logname = lib_msprintf("Drive %i", dnr + 8);
170 drive->log = log_open(logname);
171 lib_free(logname);
172
173 drive_clk[dnr] = 0L;
174 drive->clk = &drive_clk[dnr];
175 drive->mynumber = dnr;
176 }
177
178 if (driverom_load_images() < 0) {
179 resources_set_int("Drive8Type", DRIVE_TYPE_NONE);
180 resources_set_int("Drive9Type", DRIVE_TYPE_NONE);
181 resources_set_int("Drive10Type", DRIVE_TYPE_NONE);
182 resources_set_int("Drive11Type", DRIVE_TYPE_NONE);
183 return -1;
184 }
185
186 log_message(drive_log, "Finished loading ROM images.");
187 rom_loaded = 1;
188
189 drive_overflow_init();
190
191 for (dnr = 0; dnr < DRIVE_NUM; dnr++) {
192 drive = drive_context[dnr]->drive;
193
194 machine_drive_port_default(drive_context[dnr]);
195
196 if (drive_check_type(drive->type, dnr) < 1) {
197 resources_set_int_sprintf("Drive%iType", DRIVE_TYPE_NONE, dnr + 8);
198 }
199
200 machine_drive_rom_setup_image(dnr);
201 }
202
203 for (dnr = 0; dnr < DRIVE_NUM; dnr++) {
204 drive = drive_context[dnr]->drive;
205 drive->gcr = gcr_create_image();
206 drive->p64 = lib_calloc(1, sizeof(TP64Image));
207 P64ImageCreate(drive->p64);
208 drive->byte_ready_level = 1;
209 drive->byte_ready_edge = 1;
210 drive->GCR_dirty_track = 0;
211 drive->GCR_write_value = 0x55;
212 drive->GCR_track_start_ptr = NULL;
213 drive->GCR_current_track_size = 0;
214 drive->attach_clk = (CLOCK)0;
215 drive->detach_clk = (CLOCK)0;
216 drive->attach_detach_clk = (CLOCK)0;
217 drive->old_led_status = 0;
218 drive->old_half_track = 0;
219 drive->side = 0;
220 drive->GCR_image_loaded = 0;
221 drive->P64_image_loaded = 0;
222 drive->P64_dirty = 0;
223 drive->read_only = 0;
224 drive->clock_frequency = 1;
225 drive->led_last_change_clk = *(drive->clk);
226 drive->led_last_uiupdate_clk = *(drive->clk);
227 drive->led_active_ticks = 0;
228
229 rotation_reset(drive);
230
231 /* Position the R/W head on the directory track. */
232 drive_set_half_track(36, 0, drive);
233 drive_set_active_led_color(drive->type, dnr);
234 }
235
236 for (dnr = 0; dnr < DRIVE_NUM; dnr++) {
237 drive = drive_context[dnr]->drive;
238 driverom_initialize_traps(drive);
239
240 drivesync_clock_frequency(drive->type, drive);
241
242 rotation_init((drive->clock_frequency == 2) ? 1 : 0, dnr);
243
244 if (drive->type == DRIVE_TYPE_2000 || drive->type == DRIVE_TYPE_4000) {
245 drivecpu65c02_init(drive_context[dnr], drive->type);
246 } else {
247 drivecpu_init(drive_context[dnr], drive->type);
248 }
249
250 /* Make sure the sync factor is acknowledged correctly. */
251 drivesync_factor(drive_context[dnr]);
252
253 /* Make sure the traps are moved as needed. */
254 if (drive->enable) {
255 drive_enable(drive_context[dnr]);
256 }
257 }
258
259 return 0;
260 }
261
drive_shutdown(void)262 void drive_shutdown(void)
263 {
264 unsigned int dnr;
265
266 if (!drive_init_was_called) {
267 /* happens at the -help command line command*/
268 return;
269 }
270
271 for (dnr = 0; dnr < DRIVE_NUM; dnr++) {
272 if (drive_context[dnr]->drive->type == DRIVE_TYPE_2000 || drive_context[dnr]->drive->type == DRIVE_TYPE_4000) {
273 drivecpu65c02_shutdown(drive_context[dnr]);
274 } else {
275 drivecpu_shutdown(drive_context[dnr]);
276 }
277 if (drive_context[dnr]->drive->gcr) {
278 gcr_destroy_image(drive_context[dnr]->drive->gcr);
279 }
280 if (drive_context[dnr]->drive->p64) {
281 P64ImageDestroy(drive_context[dnr]->drive->p64);
282 lib_free(drive_context[dnr]->drive->p64);
283 }
284 if (drive_context[dnr]->drive->ds1216) {
285 ds1216e_destroy(drive_context[dnr]->drive->ds1216, drive_context[dnr]->drive->rtc_save);
286 }
287 }
288
289 for (dnr = 0; dnr < DRIVE_NUM; dnr++) {
290 lib_free(drive_context[dnr]->drive);
291 lib_free(drive_context[dnr]);
292 }
293 }
294
drive_set_active_led_color(unsigned int type,unsigned int dnr)295 void drive_set_active_led_color(unsigned int type, unsigned int dnr)
296 {
297 switch (type) {
298 case DRIVE_TYPE_1540: /* green power, red drive, horizontal, round */
299 case DRIVE_TYPE_1541: /* green power, red drive, horizontal, round */
300 case DRIVE_TYPE_1551: /* green power, red drive, horizontal, round */
301 case DRIVE_TYPE_1570: /* green power, red drive, horizontal, round */
302 case DRIVE_TYPE_2031: /* green power, red drive, horizontal, round */
303 case DRIVE_TYPE_1001: /* green power, red drive, horizontal, round */
304 drive_led_color[dnr] = DRIVE_LED1_RED;
305 break;
306 case DRIVE_TYPE_1571: /* red power, green drive, horizontal, line */
307 case DRIVE_TYPE_1571CR: /* red power, green drive, horizontal, line */
308 case DRIVE_TYPE_1541II: /* red power, green drive, vertical, line (some models only) */
309 case DRIVE_TYPE_1581: /* red power, green drive, vertical, line */
310 drive_led_color[dnr] = DRIVE_LED1_GREEN;
311 break;
312 case DRIVE_TYPE_2000: /* red power, green activity, red error, horizontal, line */
313 case DRIVE_TYPE_4000: /* red power, green activity, red error, horizontal, line */
314 drive_led_color[dnr] = DRIVE_LED1_GREEN | DRIVE_LED2_RED;
315 break;
316 case DRIVE_TYPE_2040: /* red drive1, red power, red drive2, horizontal, round */
317 case DRIVE_TYPE_3040: /* red drive1, red power, red drive2, horizontal, round */
318 case DRIVE_TYPE_4040: /* red drive1, red power, red drive2, horizontal, round */
319 case DRIVE_TYPE_8050: /* red drive1, green power, red drive2, horizontal, round */
320 drive_led_color[dnr] = DRIVE_LED1_RED | DRIVE_LED2_RED;
321 break;
322 case DRIVE_TYPE_8250: /* red green, green power,green, horizontal, round */
323 drive_led_color[dnr] = DRIVE_LED1_GREEN | DRIVE_LED2_GREEN; /* only the LP version is RED */
324 break;
325 default:
326 drive_led_color[dnr] = DRIVE_LED1_RED;
327 break;
328 }
329 }
330
drive_set_disk_drive_type(unsigned int type,struct drive_context_s * drv)331 int drive_set_disk_drive_type(unsigned int type, struct drive_context_s *drv)
332 {
333 unsigned int dnr;
334 drive_t *drive;
335 drive_t *drive1;
336
337 dnr = drv->mynumber;
338
339 if (machine_drive_rom_check_loaded(type) < 0) {
340 return -1;
341 }
342
343 drive = drv->drive;
344 rotation_rotate_disk(drive);
345
346 drivesync_clock_frequency(type, drive);
347
348 rotation_init(0, dnr);
349 drive->type = type;
350 if (type == DRIVE_TYPE_2000 || type == DRIVE_TYPE_4000) {
351 drivecpu65c02_setup_context(drv, 0);
352 } else {
353 drivecpu_setup_context(drv, 0);
354 }
355 drive->side = 0;
356 machine_drive_rom_setup_image(dnr);
357 drivesync_factor(drv);
358 drive_set_active_led_color(type, dnr);
359
360 /* set up (relatively) easy detection of dual drives */
361 drive1 = drive_context[mk_drive1(dnr)]->drive;
362 drive->drive0 = NULL;
363 drive1->drive1 = NULL;
364 if (is_drive0(dnr) && drive_check_dual(type)) {
365 drive->drive1 = drive1;
366 drive1->drive0 = drive;
367 } else {
368 drive->drive1 = NULL;
369 drive1->drive0 = NULL;
370 }
371
372 if (type == DRIVE_TYPE_2000 || type == DRIVE_TYPE_4000) {
373 drivecpu65c02_init(drv, type);
374 } else {
375 drivecpu_init(drv, type);
376 }
377
378 return 0;
379 }
380
drive_get_disk_drive_type(int dnr)381 int drive_get_disk_drive_type(int dnr)
382 {
383 if (dnr >= 0 && dnr < DRIVE_NUM) {
384 return drive_context[dnr]->drive->type;
385 }
386
387 return DRIVE_TYPE_NONE;
388 }
389
drive_enable_update_ui(drive_context_t * drv)390 void drive_enable_update_ui(drive_context_t *drv)
391 {
392 int i;
393 unsigned int enabled_drives = 0;
394
395 for (i = 0; i < DRIVE_NUM; i++) {
396 unsigned int the_drive;
397 drive_t *drive = drive_context[i]->drive;
398
399 the_drive = 1 << i;
400
401 if (drive->enable || (drive->drive0 && drive->drive0->enable)) {
402 enabled_drives |= the_drive;
403 drive->old_led_status = -1;
404 drive->old_half_track = -1;
405 drive->old_side = -1;
406 }
407 }
408
409 ui_enable_drive_status(enabled_drives,
410 drive_led_color);
411 }
412
413 /* Activate full drive emulation. */
drive_enable(drive_context_t * drv)414 int drive_enable(drive_context_t *drv)
415 {
416 int drive_true_emulation = 0;
417 unsigned int dnr;
418 drive_t *drive;
419
420 dnr = drv->mynumber;
421 drive = drv->drive;
422
423 /* This must come first, because this might be called before the drive
424 initialization. */
425 if (!rom_loaded) {
426 return -1;
427 }
428
429 resources_get_int("DriveTrueEmulation", &drive_true_emulation);
430
431 /* Always disable kernal traps. */
432 if (!drive_true_emulation) {
433 return 0;
434 }
435
436 if (drive->type == DRIVE_TYPE_NONE) {
437 return 0;
438 }
439
440 /* Recalculate drive geometry. */
441 if (drive->image != NULL) {
442 drive_image_attach(drive->image, dnr + 8);
443 }
444
445 /* resync */
446 drv->cpu->stop_clk = *(drv->clk_ptr);
447
448 if (drive->type == DRIVE_TYPE_2000 || drive->type == DRIVE_TYPE_4000) {
449 drivecpu65c02_wake_up(drv);
450 } else {
451 drivecpu_wake_up(drv);
452 }
453
454 /* Make sure the UI is updated. */
455 drive_enable_update_ui(drv);
456 return 0;
457 }
458
459 /* Disable full drive emulation. */
drive_disable(drive_context_t * drv)460 void drive_disable(drive_context_t *drv)
461 {
462 int drive_true_emulation = 0;
463 drive_t *drive;
464
465 drive = drv->drive;
466
467 /* This must come first, because this might be called before the true
468 drive initialization. */
469 drive->enable = 0;
470
471 resources_get_int("DriveTrueEmulation", &drive_true_emulation);
472
473 if (rom_loaded) {
474 if (drive->type == DRIVE_TYPE_2000 || drive->type == DRIVE_TYPE_4000) {
475 drivecpu65c02_sleep(drv);
476 } else {
477 drivecpu_sleep(drv);
478 }
479 machine_drive_port_default(drv);
480
481 drive_gcr_data_writeback(drive);
482 }
483
484 /* Make sure the UI is updated. */
485 drive_enable_update_ui(drv);
486 }
487
drive_cpu_monitor_interface_get(unsigned int dnr)488 monitor_interface_t *drive_cpu_monitor_interface_get(unsigned int dnr)
489 {
490 return drive_context[dnr]->cpu->monitor_interface;
491 }
492
drive_cpu_early_init_all(void)493 void drive_cpu_early_init_all(void)
494 {
495 unsigned int dnr;
496
497 for (dnr = 0; dnr < DRIVE_NUM; dnr++) {
498 machine_drive_init(drive_context[dnr]);
499 }
500 }
501
drive_cpu_prevent_clk_overflow_all(CLOCK sub)502 void drive_cpu_prevent_clk_overflow_all(CLOCK sub)
503 {
504 unsigned int dnr;
505
506 for (dnr = 0; dnr < DRIVE_NUM; dnr++) {
507 drive_t *drive = drive_context[dnr]->drive;
508 if (drive->type == DRIVE_TYPE_2000 || drive->type == DRIVE_TYPE_4000) {
509 drivecpu65c02_prevent_clk_overflow(drive_context[dnr], sub);
510 } else {
511 drivecpu_prevent_clk_overflow(drive_context[dnr], sub);
512 }
513 }
514 }
515
drive_cpu_trigger_reset(unsigned int dnr)516 void drive_cpu_trigger_reset(unsigned int dnr)
517 {
518 drive_t *drive = drive_context[dnr]->drive;
519 if (drive->type == DRIVE_TYPE_2000 || drive->type == DRIVE_TYPE_4000) {
520 drivecpu65c02_trigger_reset(dnr);
521 } else {
522 drivecpu_trigger_reset(dnr);
523 }
524 }
525
526 /* called by machine_specific_reset() */
drive_reset(void)527 void drive_reset(void)
528 {
529 unsigned int dnr;
530 drive_t *drive;
531
532 for (dnr = 0; dnr < DRIVE_NUM; dnr++) {
533 drive = drive_context[dnr]->drive;
534
535 if (drive->type == DRIVE_TYPE_2000 || drive->type == DRIVE_TYPE_4000) {
536 drivecpu65c02_reset(drive_context[dnr]);
537 } else {
538 drivecpu_reset(drive_context[dnr]);
539 }
540
541 drive->led_last_change_clk = *(drive->clk);
542 drive->led_last_uiupdate_clk = *(drive->clk);
543 drive->led_active_ticks = 0;
544 }
545 }
546
547 /* Move the head to half track `num'. */
drive_set_half_track(int num,int side,drive_t * dptr)548 void drive_set_half_track(int num, int side, drive_t *dptr)
549 {
550 int tmp;
551 if ((dptr->type == DRIVE_TYPE_1540
552 || dptr->type == DRIVE_TYPE_1541
553 || dptr->type == DRIVE_TYPE_1541II
554 || dptr->type == DRIVE_TYPE_1551
555 || dptr->type == DRIVE_TYPE_1570
556 || dptr->type == DRIVE_TYPE_2031) && (num > DRIVE_HALFTRACKS_1541)) {
557 num = DRIVE_HALFTRACKS_1541;
558 }
559 if ((dptr->type == DRIVE_TYPE_1571 || dptr->type == DRIVE_TYPE_1571CR)
560 && (num > DRIVE_HALFTRACKS_1571)) {
561 num = DRIVE_HALFTRACKS_1571;
562 }
563 if (num < 2) {
564 num = 2;
565 }
566
567 if (dptr->current_half_track != num || dptr->side != side) {
568 dptr->current_half_track = num;
569 if (dptr->p64) {
570 dptr->p64->PulseStreams[dptr->side][dptr->current_half_track].CurrentIndex = -1;
571 }
572 }
573 dptr->side = side;
574
575 /* FIXME: why would the offset be different for D71 and G71? */
576 tmp = (dptr->image && dptr->image->type == DISK_IMAGE_TYPE_G71) ? DRIVE_HALFTRACKS_1571 : 70;
577
578 dptr->GCR_track_start_ptr = dptr->gcr->tracks[dptr->current_half_track - 2 + (dptr->side * tmp)].data;
579
580 if (dptr->GCR_current_track_size != 0) {
581 dptr->GCR_head_offset = (dptr->GCR_head_offset
582 * dptr->gcr->tracks[dptr->current_half_track - 2 + (dptr->side * tmp)].size)
583 / dptr->GCR_current_track_size;
584 } else {
585 dptr->GCR_head_offset = 0;
586 }
587
588 dptr->GCR_current_track_size =
589 dptr->gcr->tracks[dptr->current_half_track - 2 + (dptr->side * tmp)].size;
590 }
591
592 /*-------------------------------------------------------------------------- */
593
594 /* Increment the head position by `step' half-tracks. Valid values
595 for `step' are `+1', '+2' and `-1'. */
drive_move_head(int step,drive_t * drive)596 void drive_move_head(int step, drive_t *drive)
597 {
598 drive_gcr_data_writeback(drive);
599 drive_sound_head(drive->current_half_track, step, drive->mynumber);
600 drive_set_half_track(drive->current_half_track + step, drive->side, drive);
601 }
602
drive_gcr_data_writeback(drive_t * drive)603 void drive_gcr_data_writeback(drive_t *drive)
604 {
605 int extend;
606 unsigned int half_track, track;
607 int tmp;
608
609 if (drive->image == NULL) {
610 return;
611 }
612
613 /* FIXME: why would the offset be different for D71 and G71? */
614 tmp = (drive->image && drive->image->type == DISK_IMAGE_TYPE_G71) ? DRIVE_HALFTRACKS_1571 : 70;
615 half_track = drive->current_half_track + (drive->side * tmp);
616 track = drive->current_half_track / 2;
617
618 if (drive->image->type == DISK_IMAGE_TYPE_P64) {
619 return;
620 }
621
622 if (!(drive->GCR_dirty_track)) {
623 return;
624 }
625
626 if ((drive->image->type == DISK_IMAGE_TYPE_G64)
627 || (drive->image->type == DISK_IMAGE_TYPE_G71)) {
628 disk_image_write_half_track(drive->image, half_track,
629 &drive->gcr->tracks[half_track - 2]);
630 drive->GCR_dirty_track = 0;
631 return;
632 }
633
634 if (half_track > drive->image->max_half_tracks) {
635 drive->GCR_dirty_track = 0;
636 return;
637 }
638 if (track > drive->image->tracks) {
639 switch (drive->extend_image_policy) {
640 case DRIVE_EXTEND_NEVER:
641 drive->ask_extend_disk_image = 1;
642 drive->GCR_dirty_track = 0;
643 return;
644 case DRIVE_EXTEND_ASK:
645 if (drive->ask_extend_disk_image == 1) {
646 extend = ui_extend_image_dialog();
647 if (extend == 0) {
648 drive->GCR_dirty_track = 0;
649 drive->ask_extend_disk_image = 0;
650 return;
651 }
652 drive->ask_extend_disk_image = 2;
653 } else if (drive->ask_extend_disk_image == 0) {
654 drive->GCR_dirty_track = 0;
655 return;
656 }
657 break;
658 case DRIVE_EXTEND_ACCESS:
659 drive->ask_extend_disk_image = 1;
660 break;
661 }
662 }
663
664 disk_image_write_half_track(drive->image, half_track,
665 &drive->gcr->tracks[half_track - 2]);
666
667 drive->GCR_dirty_track = 0;
668 }
669
drive_gcr_data_writeback_all(void)670 void drive_gcr_data_writeback_all(void)
671 {
672 drive_t *drive;
673 unsigned int i;
674 #ifdef __LIBRETRO__
675 if(!drive_context[0])
676 return;
677 #endif
678 for (i = 0; i < DRIVE_NUM; i++) {
679 drive = drive_context[i]->drive;
680 drive_gcr_data_writeback(drive);
681 if (drive->P64_image_loaded && drive->image && drive->image->p64) {
682 if (drive->image->type == DISK_IMAGE_TYPE_P64) {
683 if (drive->P64_dirty) {
684 drive->P64_dirty = 0;
685 disk_image_write_p64_image(drive->image);
686 }
687 }
688 }
689 }
690 }
691
692 /* ------------------------------------------------------------------------- */
693
drive_led_update(drive_t * drive,drive_t * drive0)694 static void drive_led_update(drive_t *drive, drive_t *drive0)
695 {
696 int my_led_status = 0;
697 CLOCK led_period;
698 unsigned int led_pwm;
699
700 /* Actually update the LED status only if the `trap idle'
701 idling method is being used, as the LED status could be
702 incorrect otherwise. */
703
704 if (drive0->idling_method != DRIVE_IDLE_SKIP_CYCLES) {
705 my_led_status = drive->led_status;
706 }
707
708 /* Update remaining led clock ticks. */
709 if (drive->led_status & 1) {
710 drive->led_active_ticks += *(drive0->clk)
711 - drive->led_last_change_clk;
712 }
713 drive->led_last_change_clk = *(drive0->clk);
714
715 led_period = *(drive0->clk) - drive->led_last_uiupdate_clk;
716 drive->led_last_uiupdate_clk = *(drive0->clk);
717
718 if (led_period == 0) {
719 return;
720 }
721
722 if (drive->led_active_ticks > led_period) {
723 /* during startup it has been observer that led_pwm > 1000,
724 which potentially breaks several UIs */
725 /* this also happens when the drive is reset from UI
726 and the LED was on */
727 led_pwm = 1000;
728 } else {
729 led_pwm = drive->led_active_ticks * 1000 / led_period;
730 }
731 assert(led_pwm <= MAX_PWM);
732 if (led_pwm > MAX_PWM) {
733 led_pwm = MAX_PWM;
734 }
735
736 drive->led_active_ticks = 0;
737
738 if (led_pwm != drive->led_last_pwm
739 || my_led_status != drive->old_led_status) {
740 ui_display_drive_led(drive->mynumber, led_pwm,
741 (my_led_status & 2) ? 1000 : 0);
742 drive->led_last_pwm = led_pwm;
743 drive->old_led_status = my_led_status;
744 }
745 }
746
747 #ifdef __LIBRETRO__
748 #include <stdbool.h>
749 #include "libretro-core.h"
750 extern unsigned int opt_autoloadwarp;
751 extern unsigned int retro_warpmode;
752 extern int retro_warp_mode_enabled();
753 extern bool retro_disk_get_eject_state();
754 static int warpmode_counter_ledon = 0;
755 static int warpmode_counter_ledoff = 0;
756 static int drive_half_track_prev = 0;
757 #endif
758
759 /* Update the status bar in the UI. */
drive_update_ui_status(void)760 void drive_update_ui_status(void)
761 {
762 int i;
763
764 if (console_mode || (machine_class == VICE_MACHINE_VSID)) {
765 return;
766 }
767
768 /* Update the LEDs and the track indicators. */
769 for (i = 0; i < DRIVE_NUM; i++) {
770 drive_t *drive = drive_context[i]->drive;
771 drive_t *drive0 = drive->drive0;
772 int dual = drive0 && drive0->enable;
773
774 if (drive->enable || dual) {
775 if (!drive0) {
776 drive0 = drive;
777 }
778
779 drive_led_update(drive, drive0);
780
781 if (drive->current_half_track != drive->old_half_track
782 || drive->side != drive->old_side) {
783 drive->old_half_track = drive->current_half_track;
784 drive->old_side = drive->side;
785 dual = dual || drive->drive1; /* also include drive 0 */
786 ui_display_drive_track(i,
787 dual ? 0 : 8,
788 drive->current_half_track + (drive->side * DRIVE_HALFTRACKS_1571));
789 }
790 #ifdef __LIBRETRO__
791 if (opt_autoloadwarp & AUTOLOADWARP_DISK && !retro_warpmode && !retro_disk_get_eject_state())
792 {
793 int warp = -1;
794 int drive_half_track = drive->current_half_track;
795 int drive_led_status = drive->led_status;
796
797 if ((drive_half_track != drive_half_track_prev) && !retro_warp_mode_enabled())
798 {
799 warpmode_counter_ledon = 0;
800 warpmode_counter_ledoff = 0;
801 warp = 1;
802 }
803 else if ((drive_half_track == drive_half_track_prev && drive->led_status) && retro_warp_mode_enabled())
804 {
805 warpmode_counter_ledon++;
806 warpmode_counter_ledoff = 0;
807 if (warpmode_counter_ledon > 998)
808 warp = 2;
809 }
810 else if ((drive_half_track == drive_half_track_prev && !drive->led_status) && retro_warp_mode_enabled())
811 {
812 warpmode_counter_ledon = 0;
813 warpmode_counter_ledoff++;
814 if (warpmode_counter_ledoff > 23)
815 warp = 0;
816 }
817 else
818 {
819 warpmode_counter_ledon = 0;
820 warpmode_counter_ledoff = 0;
821 warp = -2;
822 }
823
824 if (warp > -1)
825 {
826 resources_set_int("WarpMode", (warp > 1) ? 0 : warp);
827 #if 0
828 printf("Disk Warp:%2d track:%3d prev:%3d led:%d timer:%3d,%3d\n",
829 warp, drive_half_track, drive_half_track_prev, drive_led_status,
830 warpmode_counter_ledoff, warpmode_counter_ledon);
831 #endif
832 }
833 drive_half_track_prev = drive_half_track;
834 }
835 #endif
836 }
837 }
838 }
839
drive_num_leds(unsigned int dnr)840 int drive_num_leds(unsigned int dnr)
841 {
842 drive_t *drive = drive_context[dnr]->drive;
843
844 switch (drive->type) {
845 case DRIVE_TYPE_2040:
846 case DRIVE_TYPE_3040:
847 case DRIVE_TYPE_4040:
848 case DRIVE_TYPE_8050:
849 case DRIVE_TYPE_8250:
850 case DRIVE_TYPE_2000:
851 case DRIVE_TYPE_4000:
852 return 2;
853 default:
854 return 1;
855 }
856 }
857
drive_cpu_execute_one(drive_context_t * drv,CLOCK clk_value)858 void drive_cpu_execute_one(drive_context_t *drv, CLOCK clk_value)
859 {
860 drive_t *drive = drv->drive;
861
862 if (drive->type == DRIVE_TYPE_2000 || drive->type == DRIVE_TYPE_4000) {
863 drivecpu65c02_execute(drv, clk_value);
864 } else {
865 drivecpu_execute(drv, clk_value);
866 }
867 }
868
drive_cpu_execute_all(CLOCK clk_value)869 void drive_cpu_execute_all(CLOCK clk_value)
870 {
871 unsigned int dnr;
872 drive_t *drive;
873
874 for (dnr = 0; dnr < DRIVE_NUM; dnr++) {
875 drive = drive_context[dnr]->drive;
876 if (drive->enable) {
877 drive_cpu_execute_one(drive_context[dnr], clk_value);
878 }
879 }
880 }
881
drive_cpu_set_overflow(drive_context_t * drv)882 void drive_cpu_set_overflow(drive_context_t *drv)
883 {
884 drive_t *drive = drv->drive;
885
886 if (drive->type == DRIVE_TYPE_2000 || drive->type == DRIVE_TYPE_4000) {
887 /* nothing */
888 } else {
889 drivecpu_set_overflow(drv);
890 }
891 }
892
893 /* This is called at every vsync. */
drive_vsync_hook(void)894 void drive_vsync_hook(void)
895 {
896 unsigned int dnr;
897
898 drive_update_ui_status();
899
900 for (dnr = 0; dnr < DRIVE_NUM; dnr++) {
901 drive_t *drive = drive_context[dnr]->drive;
902 if (drive->enable) {
903 if (drive->idling_method != DRIVE_IDLE_SKIP_CYCLES) {
904 drive_cpu_execute_one(drive_context[dnr], maincpu_clk);
905 }
906 if (drive->idling_method == DRIVE_IDLE_NO_IDLE) {
907 /* if drive is never idle, also rotate the disk. this prevents
908 * huge peaks in cpu usage when the drive must catch up with
909 * a longer period of time.
910 */
911 rotation_rotate_disk(drive);
912 }
913 /* printf("drive_vsync_hook drv %d @clk:%d\n", dnr, maincpu_clk); */
914 }
915 }
916 }
917
918 /* ------------------------------------------------------------------------- */
919
drive_setup_context_for_drive(drive_context_t * drv,unsigned int dnr)920 static void drive_setup_context_for_drive(drive_context_t *drv,
921 unsigned int dnr)
922 {
923 drv->mynumber = dnr;
924 drv->drive = lib_calloc(1, sizeof(drive_t));
925 drv->clk_ptr = &drive_clk[dnr];
926
927 drivecpu_setup_context(drv, 1); /* no need for 65c02, only allocating common stuff */
928
929 machine_drive_setup_context(drv);
930 }
931
drive_setup_context(void)932 void drive_setup_context(void)
933 {
934 unsigned int dnr;
935
936 for (dnr = 0; dnr < DRIVE_NUM; dnr++) {
937 drive_context[dnr] = lib_calloc(1, sizeof(drive_context_t));
938 drive_setup_context_for_drive(drive_context[dnr], dnr);
939 }
940 }
941