fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * pce *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/arch/macplus/iwm.c *
7 * Created: 2007-11-25 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2007-2023 Hampa Hug <hampa@hampa.ch> *
9 *****************************************************************************/
10
11/*****************************************************************************
12 * This program is free software. You can redistribute it and / or modify it *
13 * under the terms of the GNU General Public License version 2 as published *
14 * by the Free Software Foundation. *
15 * *
16 * This program is distributed in the hope that it will be useful, but *
17 * WITHOUT ANY WARRANTY, without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
19 * Public License for more details. *
20 *****************************************************************************/
21
22
23#include "main.h"
24#include "iwm.h"
25#include "iwm-io.h"
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30
31#include <drivers/block/block.h>
32#include <lib/console.h>
33
34
35#define MAC_IWM_CA0 0x01
36#define MAC_IWM_CA1 0x02
37#define MAC_IWM_CA2 0x04
38#define MAC_IWM_LSTRB 0x08
39#define MAC_IWM_ENABLE 0x10
40#define MAC_IWM_SELECT 0x20
41#define MAC_IWM_Q6 0x40
42#define MAC_IWM_Q7 0x80
43
44
45#ifndef DEBUG_IWM
46#define DEBUG_IWM 0
47#endif
48
49
50static unsigned char pwm_tab[64] = {
51 0x00, 0x2b, 0x30, 0x2a, 0x2f, 0x04, 0x35, 0x29,
52 0x2e, 0x0c, 0x3a, 0x03, 0x34, 0x19, 0x09, 0x28,
53 0x2d, 0x37, 0x0e, 0x0b, 0x39, 0x20, 0x1e, 0x02,
54 0x33, 0x1c, 0x11, 0x18, 0x08, 0x15, 0x3f, 0x27,
55 0x2c, 0x31, 0x05, 0x36, 0x0d, 0x3b, 0x1a, 0x0a,
56 0x38, 0x0f, 0x21, 0x1f, 0x1d, 0x12, 0x16, 0x01,
57 0x32, 0x06, 0x3c, 0x1b, 0x10, 0x22, 0x13, 0x17,
58 0x07, 0x3d, 0x23, 0x14, 0x3e, 0x24, 0x25, 0x26
59};
60
61
62static
63int iwm_drv_init (mac_iwm_drive_t *drv, unsigned drive)
64{
65 drv->drive = drive;
66
67 drv->dsks = NULL;
68 drv->diskid = drive;
69
70 drv->img = NULL;
71 drv->img_del = 0;
72
73 drv->auto_rotate = 0;
74 drv->use_pwm = 1;
75
76 drv->cylinders = MAC_IWM_CYLINDERS;
77 drv->heads = 1;
78
79 drv->step_direction = 0;
80 drv->stepping = 0;
81 drv->disk_inserted = 0;
82 drv->disk_switched = 0;
83 drv->motor_on = 0;
84
85 drv->cur_cyl = 0;
86 drv->cur_head = 0;
87
88 drv->cur_track = NULL;
89
90 drv->cur_track_pos = 0;
91 drv->cur_track_len = 0;
92
93 drv->evt = NULL;
94
95 drv->weak_mask = 0;
96 drv->weak_run = 0;
97 drv->weak_val = 0;
98
99 drv->pwm_pos = 0;
100 drv->pwm_len = 65000;
101
102 drv->read_pos = 0;
103 drv->write_pos = 0;
104
105 drv->write_cnt = 0;
106
107 drv->input_clock = MAC_CPU_CLOCK / 10;
108 drv->input_clock_cnt = 0;
109
110 drv->track_dirty = 0;
111 drv->dirty = 0;
112
113 return (0);
114}
115
116static
117void iwm_drv_free (mac_iwm_drive_t *drv)
118{
119 if (drv->dirty) {
120 iwm_drv_save (drv);
121 }
122
123 if (drv->img_del) {
124 pri_img_del (drv->img);
125 }
126}
127
128static
129unsigned long iwm_drv_get_track_length (unsigned cyl)
130{
131 static unsigned long length_tab[5] = {
132 74640, 68240, 62200, 55980, 49760
133 };
134
135 if (cyl > 79) {
136 cyl = 79;
137 }
138
139 return (length_tab[cyl / 16]);
140}
141
142static
143void iwm_drv_write_end (mac_iwm_drive_t *drv)
144{
145 if (drv->write_cnt > drv->cur_track_len) {
146 if (drv->auto_rotate) {
147 pri_trk_rotate (drv->cur_track, drv->cur_track_pos);
148 drv->cur_track_pos = 0;
149 }
150 }
151
152 drv->write_cnt = 0;
153}
154
155static
156void iwm_drv_print_status (mac_iwm_drive_t *drv)
157{
158 char state1, state2;
159
160 if (drv->motor_on == 0) {
161 return;
162 }
163
164 state1 = drv->dirty ? '*' : ' ';
165
166 if (drv->track_dirty & 2) {
167 state2 = '+';
168 }
169 else if (drv->track_dirty & 1) {
170 state2 = '*';
171 }
172 else {
173 state2 = ' ';
174 }
175
176 pce_printf ("IWM: %cD%u %c%u/%u \r",
177 state1,
178 drv->drive + 1,
179 state2,
180 drv->cur_cyl, drv->cur_head
181 );
182}
183
184static
185void iwm_drv_select_track (mac_iwm_drive_t *drv, unsigned c, unsigned h)
186{
187 pri_trk_t *trk;
188
189 if ((c >= drv->cylinders) || (h >= drv->heads)) {
190 return;
191 }
192
193 if (drv->img == NULL) {
194 drv->img = pri_img_new();
195 }
196
197 trk = pri_img_get_track (drv->img, c, h, 1);
198
199 if (trk == NULL) {
200 return;
201 }
202
203 if (trk->size == 0) {
204 if (pri_trk_set_size (trk, iwm_drv_get_track_length (c))) {
205 return;
206 }
207 }
208
209 if (trk->clock == 0) {
210 pri_trk_set_clock (trk, 500000);
211 }
212
213 drv->cur_cyl = c;
214 drv->cur_head = h;
215 drv->cur_track = trk;
216 drv->cur_track_len = trk->size;
217
218 if (drv->cur_track_pos >= drv->cur_track_len) {
219 drv->cur_track_pos = 0;
220 }
221
222 drv->read_pos = drv->cur_track_pos;
223 drv->write_pos = drv->cur_track_pos;
224
225 drv->evt = trk->evt;
226
227 while ((drv->evt != NULL) && (drv->evt->pos < drv->cur_track_pos)) {
228 drv->evt = drv->evt->next;
229 }
230
231 drv->weak_mask = 0;
232 drv->weak_run = 0;
233 drv->weak_val = 0;
234
235 drv->track_dirty = 0;
236
237 iwm_drv_print_status (drv);
238}
239
240static
241void iwm_drv_select_head (mac_iwm_drive_t *drv, unsigned head)
242{
243 if (drv->cur_head == head) {
244 return;
245 }
246
247 iwm_drv_select_track (drv, drv->cur_cyl, head);
248}
249
250static
251int iwm_drv_get_step_direction (mac_iwm_drive_t *drv)
252{
253 int val;
254
255 val = (drv->step_direction != 0);
256
257#if DEBUG_IWM >= 2
258 mac_log_deb ("iwm: get sense: d=%u: step direction == %d\n",
259 drv->drive + 1, val
260 );
261#endif
262
263 return (val);
264}
265
266static
267int iwm_drv_get_stepping (mac_iwm_drive_t *drv)
268{
269 int val;
270
271 val = (drv->stepping != 0);
272
273 drv->stepping = 0;
274
275#if DEBUG_IWM >= 2
276 mac_log_deb ("iwm: get sense: d=%u: stepping == %d\n",
277 drv->drive + 1, val
278 );
279#endif
280
281 return (val);
282}
283
284static
285int iwm_drv_get_motor_on (mac_iwm_drive_t *drv)
286{
287 int val;
288
289 val = (drv->motor_on != 0);
290
291#if DEBUG_IWM >= 2
292 mac_log_deb ("iwm: get sense: d=%u: motor on == %d\n",
293 drv->drive + 1, val
294 );
295#endif
296
297 return (val);
298}
299
300static
301int iwm_drv_get_disk_switched (mac_iwm_drive_t *drv)
302{
303 int val;
304
305 val = (drv->disk_switched != 0);
306
307#if DEBUG_IWM >= 2
308 mac_log_deb ("iwm: get sense: d=%u: disk switched == %d\n",
309 drv->drive + 1, val
310 );
311#endif
312
313 return (val);
314}
315
316static
317int iwm_drv_get_head (mac_iwm_drive_t *drv, unsigned head)
318{
319 int val;
320
321 val = 1;
322
323#if DEBUG_IWM >= 2
324 mac_log_deb ("iwm: get sense: d=%u: head %u == %d\n",
325 drv->drive + 1, head, val
326 );
327#endif
328
329 return (val);
330}
331
332static
333int iwm_drv_get_superdrive (mac_iwm_drive_t *drv)
334{
335 int val;
336
337 val = 0;
338
339#if DEBUG_IWM >= 2
340 mac_log_deb ("iwm: get sense: d=%u: superdrive == %d\n",
341 drv->drive + 1, val
342 );
343#endif
344
345 return (val);
346}
347
348static
349int iwm_drv_get_sides (mac_iwm_drive_t *drv)
350{
351 int val;
352
353 val = (drv->heads > 1);
354
355#if DEBUG_IWM >= 2
356 mac_log_deb ("iwm: get sense: d=%u: sides == %d\n",
357 drv->drive + 1, val
358 );
359#endif
360
361 return (val);
362}
363
364static
365int iwm_drv_get_installed (mac_iwm_drive_t *drv)
366{
367 int val;
368
369 val = 1;
370
371#if DEBUG_IWM >= 2
372 mac_log_deb ("iwm: get sense: d=%u: drive installed == %d\n",
373 drv->drive + 1, val
374 );
375#endif
376
377 return (val);
378}
379
380static
381int iwm_drv_get_disk_inserted (mac_iwm_drive_t *drv)
382{
383 int val;
384
385 val = (drv->disk_inserted != 0);
386
387#if DEBUG_IWM >= 2
388 mac_log_deb ("iwm: get sense: d=%u: disk inserted == %d\n",
389 drv->drive + 1, val
390 );
391#endif
392
393 return (val);
394}
395
396static
397int iwm_drv_get_locked (mac_iwm_drive_t *drv)
398{
399 int val;
400 disk_t *dsk;
401
402 if ((dsk = dsks_get_disk (drv->dsks, drv->diskid)) != NULL){
403 val = dsk_get_readonly (dsk);
404 }
405 else {
406 val = 1;
407 }
408
409#if DEBUG_IWM >= 2
410 mac_log_deb ("iwm: get sense: d=%u: locked == %d\n",
411 drv->drive + 1, val
412 );
413#endif
414
415 return (val);
416}
417
418static
419int iwm_drv_get_track0 (mac_iwm_drive_t *drv)
420{
421 int val;
422
423 val = (drv->cur_cyl == 0);
424
425#if DEBUG_IWM >= 2
426 mac_log_deb ("iwm: get sense: d=%u: track0 == %d\n",
427 drv->drive + 1, val
428 );
429#endif
430
431 return (val);
432}
433
434static
435int iwm_drv_get_tacho (mac_iwm_drive_t *drv)
436{
437 int val;
438 unsigned long pwm;
439
440 if (drv->use_pwm) {
441 pwm = 65536 - drv->pwm_val;
442
443 val = ((((120 * pwm) / 32768) * drv->pwm_pos) / drv->pwm_len) & 1;
444 }
445 else {
446 val = ((120 * drv->cur_track_pos) / drv->cur_track_len) & 1;
447 }
448
449#if DEBUG_IWM >= 4
450 mac_log_deb ("iwm: get sense: d=%u: tacho == %d (%lu / %lu)\n",
451 drv->drive + 1, val, drv->cur_track_pos, drv->cur_track_len
452 );
453#endif
454
455 return (val);
456}
457
458static
459int iwm_drv_get_ready (mac_iwm_drive_t *drv)
460{
461 int val;
462
463 val = 1;
464
465#if DEBUG_IWM >= 2
466 mac_log_deb ("iwm: get sense: d=%u: ready == %d\n",
467 drv->drive + 1, val
468 );
469#endif
470
471 return (val);
472}
473
474static
475int iwm_drv_get_new_if (mac_iwm_drive_t *drv)
476{
477 int val;
478
479 val = 1;
480
481#if DEBUG_IWM >= 2
482 mac_log_deb ("iwm: get sense: d=%u: new interface == %d\n",
483 drv->drive + 1, val
484 );
485#endif
486
487 return (val);
488}
489
490static
491void iwm_drv_set_step_direction (mac_iwm_drive_t *drv, int val)
492{
493 drv->step_direction = (val != 0);
494
495#if DEBUG_IWM >= 2
496 mac_log_deb ("iwm: set cntrl: d=%u: step direction = %d\n",
497 drv->drive + 1, val
498 );
499#endif
500}
501
502static
503void iwm_drv_set_step (mac_iwm_drive_t *drv)
504{
505 if (drv->step_direction == 0) {
506 if (drv->cur_cyl > 0) {
507 drv->cur_cyl -= 1;
508 }
509 }
510 else {
511 if ((drv->cur_cyl + 1) < drv->cylinders) {
512 drv->cur_cyl += 1;
513 }
514 }
515
516 drv->stepping = 1;
517
518 iwm_drv_select_track (drv, drv->cur_cyl, drv->cur_head);
519
520#if DEBUG_IWM >= 2
521 mac_log_deb ("iwm: drive %u step to track %u\n",
522 drv->drive + 1, drv->cur_cyl
523 );
524#endif
525}
526
527static
528void iwm_drv_set_motor_on (mac_iwm_drive_t *drv, int val)
529{
530 if (drv->motor_on == (val != 0)) {
531 return;
532 }
533
534 drv->motor_on = (val != 0);
535
536#if DEBUG_IWM >= 1
537 mac_log_deb ("iwm: drive %u motor %s\n",
538 drv->drive + 1, val ? "on" : "off"
539 );
540#elif DEBUG_IWM >= 2
541 mac_log_deb ("iwm: set cntrl: d=%u: motor %s\n",
542 drv->drive + 1, val ? "on" : "off"
543 );
544#endif
545}
546
547static
548void iwm_drv_set_disk_switched (mac_iwm_drive_t *drv)
549{
550 drv->disk_switched = 0;
551
552#if DEBUG_IWM >= 2
553 mac_log_deb ("iwm: set cntrl: d=%u: reset disk switched\n",
554 drv->drive + 1
555 );
556#endif
557}
558
559static
560void iwm_drv_set_eject (mac_iwm_drive_t *drv)
561{
562 drv->disk_inserted = 0;
563
564#if DEBUG_IWM >= 0
565 mac_log_deb ("iwm: drive %u eject\n", drv->drive + 1);
566#elif DEBUG_IWM >= 2
567 mac_log_deb ("iwm: set cntrl: d=%u: eject\n", drv->drive + 1);
568#endif
569
570 if (drv->dirty) {
571 iwm_drv_save (drv);
572 }
573
574 if (drv->img_del) {
575 pri_img_del (drv->img);
576 }
577
578 drv->img = NULL;
579 drv->img_del = 0;
580
581 drv->cur_track = NULL;
582 drv->evt = NULL;
583}
584
585void mac_iwm_init (mac_iwm_t *iwm)
586{
587 unsigned i;
588
589 iwm->lines = 0;
590 iwm->head_sel = 0;
591
592 iwm->status = 0;
593 iwm->mode = 0;
594 iwm->handshake = 0x7f;
595
596 iwm->writing = 0;
597
598 iwm->shift_cnt = 0;
599 iwm->shift = 0;
600
601 iwm->read_buf = 0;
602 iwm->write_buf = 0;
603
604 iwm->read_zero_cnt = 0;
605
606 iwm->pwm_val = 0;
607
608 iwm->rand = 1;
609
610 for (i = 0; i < MAC_IWM_DRIVES; i++) {
611 iwm_drv_init (&iwm->drv[i], i);
612 }
613
614 iwm->curdrv = &iwm->drv[0];
615
616 iwm->set_motor_val = 0;
617 iwm->set_motor_ext = NULL;
618 iwm->set_motor = NULL;
619}
620
621void mac_iwm_free (mac_iwm_t *iwm)
622{
623 unsigned i;
624
625 for (i = 0; i < MAC_IWM_DRIVES; i++) {
626 iwm_drv_free (&iwm->drv[i]);
627 }
628}
629
630static
631int iwm_get_random (mac_iwm_t *iwm)
632{
633 if (iwm->rand & 1) {
634 iwm->rand = (iwm->rand >> 1) ^ 0x80000057;
635 }
636 else {
637 iwm->rand = iwm->rand >> 1;
638 }
639
640 return (iwm->rand & 1);
641}
642
643void mac_iwm_set_motor_fct (mac_iwm_t *iwm, void *ext, void *fct)
644{
645 iwm->set_motor_ext = ext;
646 iwm->set_motor = fct;
647}
648
649void mac_iwm_enable_pwm (mac_iwm_t *iwm, unsigned drive, int val)
650{
651 if (drive < MAC_IWM_DRIVES) {
652 iwm->drv[drive].use_pwm = (val != 0);
653 }
654}
655
656int mac_iwm_set_heads (mac_iwm_t *iwm, unsigned drive, unsigned heads)
657{
658 mac_iwm_drive_t *drv;
659
660 if (drive >= MAC_IWM_DRIVES) {
661 return (1);
662 }
663
664 if (heads > MAC_IWM_HEADS) {
665 return (1);
666 }
667
668 drv = &iwm->drv[drive];
669
670 drv->heads = heads;
671
672 if (drv->cur_head >= drv->heads) {
673 iwm_drv_select_track (drv, drv->cur_cyl, 0);
674 }
675
676 return (0);
677}
678
679void mac_iwm_set_disks (mac_iwm_t *iwm, disks_t *dsks)
680{
681 unsigned i;
682
683 for (i = 0; i < MAC_IWM_DRIVES; i++) {
684 iwm->drv[i].dsks = dsks;
685 }
686}
687
688void mac_iwm_set_disk_id (mac_iwm_t *iwm, unsigned drive, unsigned id)
689{
690 if (drive < MAC_IWM_DRIVES) {
691 iwm->drv[drive].diskid = id;
692 }
693}
694
695void mac_iwm_flush_disk (mac_iwm_t *iwm, unsigned id)
696{
697 unsigned i;
698
699 for (i = 0; i < MAC_IWM_DRIVES; i++) {
700 if (iwm->drv[i].diskid == id) {
701 iwm_drv_set_eject (iwm->drv + i);
702 }
703 }
704}
705
706void mac_iwm_insert_disk (mac_iwm_t *iwm, unsigned id)
707{
708 unsigned i;
709
710 for (i = 0; i < MAC_IWM_DRIVES; i++) {
711 if (iwm->drv[i].diskid == id) {
712 mac_iwm_insert (iwm, i);
713 }
714 }
715}
716
717void mac_iwm_set_auto_rotate (mac_iwm_t *iwm, unsigned drive, int val)
718{
719 if (drive >= MAC_IWM_DRIVES) {
720 return;
721 }
722
723 iwm->drv[drive].auto_rotate = (val != 0);
724}
725
726static
727void mac_iwm_select_drive (mac_iwm_t *iwm, unsigned drive)
728{
729 if (drive >= MAC_IWM_DRIVES) {
730 drive = 0;
731 }
732
733 iwm->curdrv = &iwm->drv[drive];
734
735 iwm_drv_select_track (iwm->curdrv, iwm->curdrv->cur_cyl, iwm->head_sel);
736}
737
738void mac_iwm_set_drive_sel (mac_iwm_t *iwm, unsigned char val)
739{
740 val = (val != 0);
741
742 if (iwm->drive_sel == val) {
743 return;
744 }
745
746 iwm->drive_sel = val;
747
748 if ((iwm->lines & MAC_IWM_SELECT) == 0) {
749 mac_iwm_select_drive (iwm, iwm->drive_sel ? 2 : 0);
750 }
751
752#if DEBUG_IWM >= 2
753 mac_log_deb ("iwm: drive sel = %d\n", iwm->drive_sel);
754#endif
755}
756
757void mac_iwm_set_head_sel (mac_iwm_t *iwm, unsigned char val)
758{
759 val = (val != 0);
760
761 if (iwm->head_sel == val) {
762 return;
763 }
764
765 iwm->head_sel = val;
766
767 iwm_drv_select_head (iwm->curdrv, val);
768
769#if DEBUG_IWM >= 2
770 mac_log_deb ("iwm: head sel = %d\n", iwm->head_sel);
771#endif
772}
773
774void mac_iwm_set_pwm (mac_iwm_t *iwm, const unsigned char *buf, unsigned cnt)
775{
776 unsigned long pwm, val;
777
778 pwm = iwm->pwm_val;
779
780 while (cnt > 0) {
781 val = 1024UL * pwm_tab[*(buf++) & 0x3f];
782 pwm = (31 * pwm + val) / 32;
783 cnt -= 1;
784 }
785
786#if DEBUG_IWM >= 2
787 if (pwm != iwm->pwm_val) {
788 mac_log_deb ("iwm: drive %u set pwm to %lu\n",
789 iwm->curdrv->drive + 1, pwm
790 );
791 }
792#endif
793
794 iwm->pwm_val = pwm;
795 iwm->curdrv->pwm_val = pwm;
796}
797
798static
799void mac_iwm_set_motor (mac_iwm_t *iwm)
800{
801 unsigned i;
802 unsigned char v;
803
804 v = 0;
805
806 for (i = 0; i < MAC_IWM_DRIVES; i++) {
807 if (iwm->drv[i].motor_on) {
808 v = 1;
809 break;
810 }
811 }
812
813 if (iwm->set_motor_val == v) {
814 return;
815 }
816
817 iwm->set_motor_val = v;
818
819 if (iwm->set_motor != NULL) {
820 iwm->set_motor (iwm->set_motor_ext, v);
821 }
822}
823
824void mac_iwm_insert (mac_iwm_t *iwm, unsigned drive)
825{
826 mac_iwm_drive_t *drv;
827
828 if (drive >= MAC_IWM_DRIVES) {
829 return;
830 }
831
832 drv = &iwm->drv[drive];
833
834 if (drv->disk_inserted) {
835 return;
836 }
837
838#if DEBUG_IWM >= 1
839 mac_log_deb ("iwm: drive %u insert\n", drive + 1);
840#endif
841
842 if (iwm_drv_load (drv) == 0) {
843 drv->disk_inserted = 1;
844 iwm_drv_select_track (drv, drv->cur_cyl, drv->cur_head);
845 }
846}
847
848static
849int mac_iwm_get_drive_status (mac_iwm_t *iwm)
850{
851 unsigned reg;
852 mac_iwm_drive_t *drv;
853
854 reg = (iwm->lines & 7) | (iwm->head_sel ? 8 : 0);
855 drv = iwm->curdrv;
856
857 switch (reg) {
858 case 0:
859 return (iwm_drv_get_step_direction (drv) == 0);
860
861 case 1:
862 return (iwm_drv_get_stepping (drv) == 0);
863
864 case 2:
865 return (iwm_drv_get_motor_on (drv) == 0);
866
867 case 3:
868 return (iwm_drv_get_disk_switched (drv) != 0);
869
870 case 4:
871 return (iwm_drv_get_head (drv, 0) == 0);
872
873 case 5:
874 return (iwm_drv_get_superdrive (drv));
875
876 case 6:
877 return (iwm_drv_get_sides (drv));
878
879 case 7:
880 return (iwm_drv_get_installed (drv) == 0);
881
882 case 8:
883 return (iwm_drv_get_disk_inserted (drv) == 0);
884
885 case 9:
886 return (iwm_drv_get_locked (drv) == 0);
887
888 case 10:
889 return (iwm_drv_get_track0 (drv) == 0);
890
891 case 11:
892 return (iwm_drv_get_tacho (drv) == 0);
893
894 case 12:
895 return (iwm_drv_get_head (drv, 1) == 0);
896
897 case 13:
898 return (1);
899
900 case 14:
901 return (iwm_drv_get_ready (drv) == 0);
902
903 case 15:
904 return (iwm_drv_get_new_if (drv));
905
906 default:
907#if DEBUG_IWM >= 1
908 mac_log_deb ("iwm: get sense: d=%u: reg 0x%02x == %d\n",
909 drv->drive + 1, reg, 0
910 );
911#endif
912 break;
913 }
914
915 return (1);
916}
917
918static
919void mac_iwm_set_drive_control (mac_iwm_t *iwm)
920{
921 int val;
922 unsigned reg;
923 mac_iwm_drive_t *drv;
924
925 reg = (iwm->lines & 3) | (iwm->head_sel ? 4 : 0);
926 val = ((iwm->lines & MAC_IWM_CA2) != 0);
927 drv = iwm->curdrv;
928
929 switch (reg) {
930 case 0:
931 iwm_drv_set_step_direction (drv, val == 0);
932 break;
933
934 case 1:
935 if (val == 0) {
936 iwm_drv_set_step (drv);
937 }
938 break;
939
940 case 2:
941 iwm_drv_set_motor_on (drv, val == 0);
942 mac_iwm_set_motor (iwm);
943 break;
944
945 case 3:
946 if (val) {
947 iwm_drv_set_eject (drv);
948 }
949 break;
950
951 case 4:
952 if (val) {
953 iwm_drv_set_disk_switched (drv);
954 }
955 break;
956
957 default:
958#if DEBUG_IWM >= 1
959 mac_log_deb ("iwm: set cntrl: d=%u: reg 0x%02x = %d\n",
960 drv->drive + 1, reg, val
961 );
962#endif
963 break;
964 }
965}
966
967static
968void mac_iwm_access_uint8 (mac_iwm_t *iwm, unsigned reg)
969{
970 switch (reg & 0x0f) {
971 case 0x00: /* ca0 low */
972 iwm->lines &= ~MAC_IWM_CA0;
973 break;
974
975 case 0x01: /* ca0 high */
976 iwm->lines |= MAC_IWM_CA0;
977 break;
978
979 case 0x02: /* ca1 low */
980 iwm->lines &= ~MAC_IWM_CA1;
981 break;
982
983 case 0x03: /* ca1 high */
984 iwm->lines |= MAC_IWM_CA1;
985 break;
986
987 case 0x04: /* ca2 low */
988 iwm->lines &= ~MAC_IWM_CA2;
989 break;
990
991 case 0x05: /* ca2 high */
992 iwm->lines |= MAC_IWM_CA2;
993 break;
994
995 case 0x06: /* lstrb low */
996 iwm->lines &= ~MAC_IWM_LSTRB;
997 break;
998
999 case 0x07: /* lstrb high */
1000 iwm->lines |= MAC_IWM_LSTRB;
1001 break;
1002
1003 case 0x08: /* enable low */
1004 iwm->lines &= ~MAC_IWM_ENABLE;
1005 iwm->status &= ~0x20;
1006 break;
1007
1008 case 0x09: /* enable high */
1009 iwm->lines |= MAC_IWM_ENABLE;
1010 iwm->status |= 0x20;
1011 break;
1012
1013 case 0x0a: /* select low */
1014 iwm->lines &= ~MAC_IWM_SELECT;
1015 mac_iwm_select_drive (iwm, iwm->drive_sel ? 2 : 0);
1016 break;
1017
1018 case 0x0b: /* select high */
1019 iwm->lines |= MAC_IWM_SELECT;
1020 mac_iwm_select_drive (iwm, 1);
1021 break;
1022
1023 case 0x0c: /* q6 low */
1024 iwm->lines &= ~MAC_IWM_Q6;
1025 break;
1026
1027 case 0x0d: /* q6 high */
1028 iwm->lines |= MAC_IWM_Q6;
1029 break;
1030
1031 case 0x0e: /* q7 low */
1032 iwm->lines &= ~MAC_IWM_Q7;
1033 break;
1034
1035 case 0x0f: /* q7 high */
1036 iwm->lines |= MAC_IWM_Q7;
1037 break;
1038 }
1039
1040 if (iwm->lines & MAC_IWM_LSTRB) {
1041 mac_iwm_set_drive_control (iwm);
1042 }
1043
1044 if ((iwm->lines & MAC_IWM_Q7) == 0) {
1045 iwm->handshake |= 0x40;
1046
1047 if (iwm->writing) {
1048 iwm->writing = 0;
1049 iwm->curdrv->track_dirty &= ~2U;
1050 iwm_drv_write_end (iwm->curdrv);
1051 iwm_drv_print_status (iwm->curdrv);
1052 }
1053 }
1054}
1055
1056unsigned char mac_iwm_get_uint8 (mac_iwm_t *iwm, unsigned long addr)
1057{
1058 unsigned char val;
1059
1060 if ((addr & 1) == 0) {
1061 return (0);
1062 }
1063
1064 addr = (addr >> 9) & 0x0f;
1065
1066 mac_iwm_access_uint8 (iwm, addr);
1067
1068 val = 0;
1069
1070 switch (iwm->lines & (MAC_IWM_Q6 | MAC_IWM_Q7)) {
1071 case 0x00: /* read data */
1072 if (iwm->lines & MAC_IWM_ENABLE) {
1073 val = iwm->read_buf;
1074 iwm->read_buf = 0;
1075 }
1076 else {
1077 val = 0xff;
1078 }
1079 break;
1080
1081 case MAC_IWM_Q6: /* read status */
1082 val = (iwm->status & 0x60) | (iwm->mode & 0x1f);
1083
1084 if (mac_iwm_get_drive_status (iwm)) {
1085 val |= 0x80;
1086 }
1087#if DEBUG_IWM >= 4
1088 mac_log_deb ("iwm: read status (0x%02x)\n", val);
1089#endif
1090 break;
1091
1092 case MAC_IWM_Q7: /* read handshake */
1093 val = iwm->handshake & 0x7f;
1094
1095 if ((iwm->write_buf & 0xff00) == 0) {
1096 val |= 0x80;
1097 }
1098
1099#if DEBUG_IWM >= 3
1100 mac_log_deb ("iwm: read handshake (0x%02x)\n", val);
1101#endif
1102 break;
1103
1104 case (MAC_IWM_Q6 | MAC_IWM_Q7): /* ? */
1105#if DEBUG_IWM >= 2
1106 mac_log_deb ("iwm: get 8: %06lX -> 0x%02x\n", addr, val);
1107#endif
1108 break;
1109 }
1110
1111 return (val);
1112}
1113
1114void mac_iwm_set_uint8 (mac_iwm_t *iwm, unsigned long addr, unsigned char val)
1115{
1116 if ((addr & 1) == 0) {
1117 return;
1118 }
1119
1120 addr = (addr >> 9) & 0x0f;
1121
1122 mac_iwm_access_uint8 (iwm, addr);
1123
1124 switch (iwm->lines & (MAC_IWM_Q6 | MAC_IWM_Q7)) {
1125 case (MAC_IWM_Q6 | MAC_IWM_Q7): /* mode write */
1126 if (iwm->lines & MAC_IWM_ENABLE) {
1127 /* write data */
1128 if (iwm->writing == 0) {
1129 iwm->writing = 1;
1130 iwm->shift_cnt = 0;
1131 iwm->curdrv->write_cnt = 0;
1132 iwm->curdrv->track_dirty |= 3;
1133
1134 iwm_drv_print_status (iwm->curdrv);
1135#if DEBUG_IWM >= 1
1136 mac_log_deb (
1137 "iwm: drive %u writing track %u head %u\n",
1138 iwm->curdrv->drive + 1,
1139 iwm->curdrv->cur_cyl,
1140 iwm->curdrv->cur_head
1141 );
1142#endif
1143 }
1144
1145 iwm->write_buf = val | 0xff00;
1146#if DEBUG_IWM >= 3
1147 mac_log_deb ("iwm: write data (0x%02x)\n", val);
1148#endif
1149 }
1150 else {
1151 /* write mode */
1152 iwm->mode = val;
1153#if DEBUG_IWM >= 2
1154 mac_log_deb ("iwm: write mode (0x%02x)\n", val);
1155#endif
1156 }
1157 break;
1158
1159 default:
1160#if DEBUG_IWM >= 2
1161 mac_log_deb ("iwm: set 8: %04lX <- %02X\n", addr, val);
1162#endif
1163 break;
1164 }
1165}
1166
1167static
1168void mac_iwm_read (mac_iwm_t *iwm, mac_iwm_drive_t *drv)
1169{
1170 unsigned long p;
1171 unsigned char m;
1172 unsigned char *data;
1173
1174 if ((drv->cur_track == NULL) || (drv->cur_track_len == 0)) {
1175 return;
1176 }
1177
1178 p = drv->read_pos / 8;
1179 m = 0x80 >> (drv->read_pos & 7);
1180
1181 data = drv->cur_track->data;
1182
1183 while (drv->read_pos != drv->cur_track_pos) {
1184 while ((drv->evt != NULL) && (drv->evt->pos == drv->read_pos)) {
1185 if (drv->evt->type == PRI_EVENT_WEAK) {
1186 drv->weak_mask |= drv->evt->val & 0xffffffff;
1187 }
1188
1189 drv->evt = drv->evt->next;
1190 }
1191
1192 iwm->shift = (iwm->shift << 1) | ((data[p] & m) != 0);
1193
1194 if (iwm->shift & 1) {
1195 iwm->read_zero_cnt = 0;
1196 }
1197 else {
1198 iwm->read_zero_cnt += 1;
1199 }
1200
1201 if ((drv->weak_run != 0) || (drv->weak_mask != 0)) {
1202 if (drv->weak_run > 0) {
1203 iwm->shift &= ~1U;
1204 iwm->shift |= drv->weak_val & 1;
1205 drv->weak_val >>= 1;
1206 drv->weak_run -= 1;
1207 }
1208 else if (drv->weak_mask & 0x80000000) {
1209 iwm->shift &= ~1U;
1210 iwm->shift |= iwm_get_random (iwm) & 1;
1211 }
1212
1213 if ((drv->weak_mask & 0xf0000000) == 0x60000000) {
1214 drv->weak_run = 2;
1215 drv->weak_val = 1;
1216 drv->weak_val <<= iwm_get_random (iwm) & 1;
1217 }
1218 else if ((drv->weak_mask & 0xf8000000) == 0x70000000) {
1219 drv->weak_run = 3;
1220 drv->weak_val = 1;
1221 drv->weak_val <<= iwm_get_random (iwm) & 1;
1222 drv->weak_val <<= iwm_get_random (iwm) & 1;
1223 }
1224
1225 drv->weak_mask = (drv->weak_mask << 1) & 0xffffffff;
1226 }
1227
1228 drv->read_pos += 1;
1229
1230 if (drv->read_pos >= drv->cur_track_len) {
1231 drv->read_pos = 0;
1232 p = 0;
1233 m = 0x80;
1234 drv->evt = drv->cur_track->evt;
1235 }
1236 else if (m == 1) {
1237 m = 0x80;
1238 p += 1;
1239 }
1240 else {
1241 m >>= 1;
1242 }
1243
1244 if (iwm->shift & 0x80) {
1245 iwm->read_buf = iwm->shift;
1246 iwm->shift = 0;
1247 }
1248 }
1249}
1250
1251static
1252void mac_iwm_write (mac_iwm_t *iwm, mac_iwm_drive_t *drv)
1253{
1254 unsigned long p;
1255 unsigned char m;
1256 unsigned char *data;
1257
1258 if ((drv->cur_track == NULL) || (drv->cur_track_len == 0)) {
1259 return;
1260 }
1261
1262 p = drv->write_pos / 8;
1263 m = 0x80 >> (drv->write_pos & 7);
1264
1265 data = drv->cur_track->data;
1266
1267 while (drv->write_pos != drv->cur_track_pos) {
1268 if (iwm->shift_cnt == 0) {
1269 if ((iwm->write_buf & 0xff00) == 0) {
1270#if DEBUG_IWM >= 2
1271 mac_log_deb ("iwm: drive %u underrun\n",
1272 drv->drive + 1
1273 );
1274#endif
1275 iwm->handshake &= ~0x40;
1276 iwm->shift_cnt = 0;
1277 iwm->writing = 0;
1278 iwm->curdrv->track_dirty &= ~2U;
1279
1280 iwm_drv_write_end (drv);
1281
1282 return;
1283 }
1284
1285 iwm->shift = iwm->write_buf & 0xff;
1286 iwm->shift_cnt = 8;
1287 iwm->write_buf = 0;
1288 }
1289
1290 if (iwm->shift & 0x80) {
1291 data[p] |= m;
1292 }
1293 else {
1294 data[p] &= ~m;
1295 }
1296
1297 drv->track_dirty |= 3;
1298 drv->dirty = 1;
1299
1300 iwm->shift = (iwm->shift << 1) & 0xff;
1301 iwm->shift_cnt -= 1;
1302
1303 drv->write_pos += 1;
1304
1305 drv->write_cnt += 1;
1306
1307 if (drv->write_pos >= drv->cur_track_len) {
1308 drv->write_pos = 0;
1309 p = 0;
1310 m = 0x80;
1311 }
1312 else if (m == 1) {
1313 m = 0x80;
1314 p += 1;
1315 }
1316 else {
1317 m >>= 1;
1318 }
1319 }
1320}
1321
1322void mac_iwm_clock (mac_iwm_t *iwm, unsigned cnt)
1323{
1324 unsigned long clk, bit;
1325 mac_iwm_drive_t *drv;
1326
1327 drv = iwm->curdrv;
1328
1329 if (drv->motor_on == 0) {
1330 return;
1331 }
1332
1333 clk = drv->input_clock_cnt + 500000UL * cnt;
1334 bit = clk / drv->input_clock;
1335 clk = clk % drv->input_clock;
1336 drv->input_clock_cnt = clk;
1337
1338 if (drv->cur_track_len > 0) {
1339 drv->cur_track_pos += bit;
1340
1341 while (drv->cur_track_pos >= drv->cur_track_len) {
1342 drv->cur_track_pos -= drv->cur_track_len;
1343 }
1344 }
1345
1346 if (drv->pwm_len > 0) {
1347 drv->pwm_pos += bit;
1348
1349 if (drv->pwm_pos >= drv->pwm_len) {
1350 drv->pwm_pos -= drv->pwm_len;
1351 }
1352 }
1353
1354 if (iwm->writing) {
1355 mac_iwm_write (iwm, drv);
1356 }
1357 else if ((iwm->lines & (MAC_IWM_Q6 | MAC_IWM_Q7)) == 0) {
1358 mac_iwm_read (iwm, drv);
1359 }
1360
1361 drv->read_pos = drv->cur_track_pos;
1362 drv->write_pos = drv->cur_track_pos;
1363}