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