Subversion Repositories pentevo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
716 lvd 1
#include "std.h"
2
 
3
#include "emul.h"
4
#include "vars.h"
5
#include "wd93crc.h"
6
 
7
#include "util.h"
8
 
9
void WD1793::process()
10
{
11
   time = comp.t_states + cpu.t;
12
 
13
   if(!(sign_status & SIG_HLD) && !(system & 0x20))
14
   {
15
       seldrive->motor = 0;
16
   }
17
 
18
   if (seldrive->rawdata)
19
       status &= ~WDS_NOTRDY;
20
   else
21
       status |= WDS_NOTRDY;
22
 
23
   if (!(cmd & 0x80) || (cmd & 0xF0) == 0xD0) // seek / step commands
24
   {
25
      status &= ~WDS_INDEX;
26
 
27
      if(state != S_IDLE)
28
      {
29
          status &= ~(WDS_TRK00 | WDS_INDEX);
30
          if (!seldrive->track) status |= WDS_TRK00;
31
      }
32
 
33
      // todo: test spinning
34
      if (seldrive->rawdata && seldrive->motor && ((time+tshift) % (Z80FQ/FDD_RPS) < (Z80FQ*4/1000)))
35
      {
36
          // index every turn, len=4ms (if disk present)
37
         if(state == S_IDLE)
38
         {
39
             if(time < idx_tmo)
40
                 status |= WDS_INDEX;
41
         }
42
         else
43
         {
44
             status |= WDS_INDEX;
45
         }
46
      }
47
   }
48
 
49
   for (;;)
50
   {
51
      if(!seldrive->motor)
52
      {
53
          status |= WDS_NOTRDY;
54
      }
55
      else
56
      {
57
          status &= ~WDS_NOTRDY;
58
      }
59
 
60
      switch (state)
61
      {
62
 
63
         // ----------------------------------------------------
64
 
65
         case S_IDLE:
66
            status &= ~WDS_BUSY;
67
            if(idx_cnt >= 15 || time > idx_tmo)
68
            {
69
                idx_cnt = 15;
70
                status &= WDS_NOTRDY;
71
                status |= WDS_NOTRDY;
72
                seldrive->motor = 0;
73
                sign_status &= ~SIG_HLD;
74
            }
75
            rqs = INTRQ;
76
            return;
77
 
78
         case S_WAIT:
79
            if (time < next)
80
                return;
81
            state = state2;
82
            break;
83
 
84
         // ----------------------------------------------------
85
         // Подана команда типа 2 или 3 (read/write)/(read am/read trk/write trk)
86
         case S_DELAY_BEFORE_CMD:
87
            if (!conf.wd93_nodelay && (cmd & CMD_DELAY)) // Проверка бита E=1
88
                next += (Z80FQ*15/1000); // 15ms delay
89
            state2 = S_WAIT_HLT_RW;
90
            state = S_WAIT;
91
            break;
92
 
93
         case S_WAIT_HLT_RW:
94
            if(!(system & 0x08)) // HLT = 0 (бесконечное ожидание HLT)
95
            {
96
                return;
97
            }
98
 
99
            state = S_CMD_RW;
100
 
101
         case S_CMD_RW:
102
            if (((cmd & 0xE0) == 0xA0 || (cmd & 0xF0) == 0xF0) && conf.trdos_wp[drive])
103
            {
104
               status |= WDS_WRITEP;
105
               state = S_IDLE;
106
               break;
107
            }
108
 
109
            if ((cmd & 0xC0) == 0x80 || (cmd & 0xF8) == 0xC0)
110
            {
111
               // read/write sectors or read am - find next AM
112
               end_waiting_am = next + 5*Z80FQ/FDD_RPS; // max wait disk 5 turns
113
               find_marker();
114
               break;
115
            }
116
 
117
            if ((cmd & 0xF8) == 0xF0) // write track
118
            {
119
               rqs = DRQ;
120
               status |= WDS_DRQ;
121
               next += 3*seldrive->t.ts_byte;
122
               state2 = S_WRTRACK;
123
               state = S_WAIT;
124
               break;
125
            }
126
 
127
            if ((cmd & 0xF8) == 0xE0) // read track
128
            {
129
               load();
130
               rwptr = 0;
131
               rwlen = seldrive->t.trklen;
132
               state2 = S_READ;
133
               getindex();
134
               break;
135
            }
136
 
137
            // else unknown command
138
            state = S_IDLE;
139
            break;
140
 
141
        case S_FOUND_NEXT_ID:
142
            if (!seldrive->rawdata)
143
            { // no disk - wait again
144
               end_waiting_am = next + 5*Z80FQ/FDD_RPS;
145
        nextmk:
146
               find_marker();
147
               break;
148
            }
149
            if (next >= end_waiting_am)
150
            {
151
            nf:
152
                status |= WDS_NOTFOUND;
153
                state = S_IDLE;
154
                break;
155
            }
156
            if (foundid == -1)
157
                goto nf;
158
 
159
            status &= ~WDS_CRCERR;
160
            load();
161
 
162
            if (!(cmd & 0x80)) // verify after seek
163
            {
164
               if (seldrive->t.hdr[foundid].c != track)
165
                   goto nextmk;
166
               if (!seldrive->t.hdr[foundid].c1)
167
               {
168
                   status |= WDS_CRCERR;
169
                   goto nextmk;
170
               }
171
               state = S_IDLE; break;
172
            }
173
 
174
            if ((cmd & 0xF0) == 0xC0) // read AM
175
            {
176
               rwptr = seldrive->t.hdr[foundid].id - seldrive->t.trkd;
177
               rwlen = 6;
178
 
179
         read_first_byte:
180
               u8 data_mask = 0;
181
               if(seldrive->t.trkwp) // проверяем карту сбойных байтов
182
               {
183
                   if(seldrive->t.test_wp(rwptr))
184
                   {
185
                       data_mask = 0xFF;
186
                       seldrive->t.hdr[foundid].c1 = 0; // bad address crc
187
                   }
188
               }
189
               data = seldrive->t.trkd[rwptr++];
190
               data ^= data_mask;
191
               rwlen--;
192
               rqs = DRQ; status |= WDS_DRQ;
193
               next += seldrive->t.ts_byte;
194
               state = S_WAIT;
195
               state2 = S_READ;
196
               break;
197
            }
198
 
199
            // else R/W sector(s)
200
            if (seldrive->t.hdr[foundid].c != track || seldrive->t.hdr[foundid].n != sector)
201
                goto nextmk;
202
            if ((cmd & CMD_SIDE_CMP_FLAG) && (((cmd >> CMD_SIDE_SHIFT) ^ seldrive->t.hdr[foundid].s) & 1))
203
                goto nextmk;
204
            if (!seldrive->t.hdr[foundid].c1)
205
            {
206
                status |= WDS_CRCERR;
207
                goto nextmk;
208
            }
209
 
210
            if (cmd & 0x20) // write sector(s)
211
            {
212
               rqs = DRQ; status |= WDS_DRQ;
213
               next += seldrive->t.ts_byte*9;
214
               state = S_WAIT; state2 = S_WRSEC;
215
               break;
216
            }
217
 
218
            // read sector(s)
219
            if (!seldrive->t.hdr[foundid].data)
220
                goto nextmk; // Сектор без зоны данных
221
            if(!conf.wd93_nodelay)
222
                next += seldrive->t.ts_byte*(seldrive->t.hdr[foundid].data - seldrive->t.hdr[foundid].id); // Задержка на пропуск заголовка сектора и пробела между заголовком и зоной данных
223
            state = S_WAIT;
224
            state2 = S_RDSEC;
225
            break;
226
 
227
         case S_RDSEC:
228
            if (seldrive->t.hdr[foundid].data[-1] == 0xF8)
229
                status |= WDS_RECORDT;
230
            else
231
                status &= ~WDS_RECORDT;
232
            rwptr = seldrive->t.hdr[foundid].data - seldrive->t.trkd; // Смещение зоны данных сектора (в байтах) относительно начала трека
233
            rwlen = 128 << (seldrive->t.hdr[foundid].l & 3); // [vv]
234
            goto read_first_byte;
235
 
236
         case S_READ:
237
            if (notready())
238
                break;
239
            load();
240
 
241
            if(!seldrive->t.trkd)
242
            {
243
                status |= WDS_NOTFOUND;
244
                state = S_IDLE;
245
                break;
246
            }
247
 
248
            if (rwlen)
249
            {
250
               trdos_load = ROMLED_TIME;
251
               if (rqs & DRQ)
252
                   status |= WDS_LOST;
253
 
254
               u8 data_mask = 0;
255
               if(seldrive->t.trkwp) // проверяем карту сбойных байтов
256
               {
257
                   if(seldrive->t.test_wp(rwptr))
258
                   {
259
                       data_mask = 0xFF;
260
                       if ((cmd & 0xE0) == 0x80) // read sector
261
                       {
262
                           seldrive->t.hdr[foundid].c2 = 0; // bad data crc
263
                       }
264
                       if ((cmd & 0xF0) == 0xC0) // read address
265
                       {
266
                           seldrive->t.hdr[foundid].c1 = 0; // bad address crc
267
                       }
268
                   }
269
               }
270
               data = seldrive->t.trkd[rwptr++];
271
               data ^= data_mask;
272
               rwlen--;
273
               rqs = DRQ;
274
               status |= WDS_DRQ;
275
 
276
               if (!conf.wd93_nodelay)
277
                   next += seldrive->t.ts_byte;
278
               else
279
                   next = time + 1;
280
               state = S_WAIT;
281
               state2 = S_READ;
282
            }
283
            else
284
            {
285
               if ((cmd & 0xE0) == 0x80) // read sector
286
               {
287
                  if (!seldrive->t.hdr[foundid].c2)
288
                      status |= WDS_CRCERR;
289
                  if (cmd & CMD_MULTIPLE)
290
                  {
291
                      sector++;
292
                      state = S_CMD_RW;
293
                      break;
294
                  }
295
               }
296
 
297
               // FIXME: Временный хак для zx-format 3
298
               if (((cmd & 0xF8) == 0xE0) && (seldrive->t.trklen < MAX_TRACK_LEN)) // read track
299
               {
300
                   status |= WDS_LOST;
301
               }
302
 
303
               if ((cmd & 0xF0) == 0xC0) // read address
304
               {
305
                  if (!seldrive->t.hdr[foundid].c1)
306
                      status |= WDS_CRCERR;
307
               }
308
               state = S_IDLE;
309
            }
310
            break;
311
 
312
 
313
         case S_WRSEC:
314
            load();
315
            if (rqs & DRQ)
316
            {
317
                status |= WDS_LOST;
318
                state = S_IDLE;
319
                break;
320
            }
321
            seldrive->optype |= 1;
322
            rwptr = seldrive->t.hdr[foundid].id + 6 + 11 + 11 - seldrive->t.trkd;
323
            for (rwlen = 0; rwlen < 12; rwlen++)
324
                seldrive->t.write(rwptr++, 0, 0);
325
            for (rwlen = 0; rwlen < 3; rwlen++)
326
                seldrive->t.write(rwptr++, 0xA1, 1);
327
            seldrive->t.write(rwptr++, (cmd & CMD_WRITE_DEL)? 0xF8 : 0xFB, 0);
328
            rwlen = 128 << (seldrive->t.hdr[foundid].l & 3); // [vv]
329
            state = S_WRITE;
330
            break;
331
 
332
         case S_WRITE:
333
            if (notready())
334
                break;
335
            if (rqs & DRQ)
336
                status |= WDS_LOST, data = 0;
337
            trdos_save = ROMLED_TIME;
338
            seldrive->t.write(rwptr++, data, 0); rwlen--;
339
            if (rwptr == seldrive->t.trklen) rwptr = 0;
340
            seldrive->t.sf = JUST_SEEK; // invalidate sectors
341
            if (rwlen)
342
            {
343
               if (!conf.wd93_nodelay) next += seldrive->t.ts_byte;
344
               state = S_WAIT; state2 = S_WRITE;
345
               rqs = DRQ; status |= WDS_DRQ;
346
            }
347
            else
348
            {
349
               unsigned len = (128 << (seldrive->t.hdr[foundid].l & 3)) + 1; //[vv]
350
               unsigned char sc[2056];
351
               if (rwptr < len)
352
               {
353
                   memcpy(sc, seldrive->t.trkd + seldrive->t.trklen - rwptr, rwptr);
354
                   memcpy(sc + rwptr, seldrive->t.trkd, len - rwptr);
355
               }
356
               else
357
                   memcpy(sc, seldrive->t.trkd + rwptr - len, len);
358
               unsigned crc = wd93_crc(sc, len);
359
               seldrive->t.write(rwptr++, (BYTE)crc, 0);
360
               seldrive->t.write(rwptr++, (BYTE)(crc >> 8), 0);
361
               seldrive->t.write(rwptr, 0xFF, 0);
362
               if (cmd & CMD_MULTIPLE)
363
               {
364
                   sector++;
365
                   state = S_CMD_RW;
366
                   break;
367
               }
368
               state = S_IDLE;
369
            }
370
            break;
371
 
372
         case S_WRTRACK:
373
            if (rqs & DRQ)
374
            {
375
                status |= WDS_LOST;
376
                state = S_IDLE;
377
                break;
378
            }
379
            seldrive->optype |= 2;
380
            state2 = S_WR_TRACK_DATA;
381
            start_crc = 0;
382
            getindex();
383
            end_waiting_am = next + 5 * Z80FQ /FDD_RPS;
384
         break;
385
 
386
         case S_WR_TRACK_DATA:
387
         {
388
            if (notready())
389
                break;
390
            trdos_format = ROMLED_TIME;
391
            if (rqs & DRQ)
392
            {
393
                status |= WDS_LOST;
394
                data = 0;
395
            }
396
            seldrive->t.seek(seldrive, seldrive->track, side, JUST_SEEK);
397
            seldrive->t.sf = JUST_SEEK; // invalidate sectors
398
 
399
            if(!seldrive->t.trkd)
400
            {
401
                state = S_IDLE;
402
                break;
403
            }
404
 
405
            unsigned char marker = 0, byte = data;
406
            unsigned crc;
407
            switch(data)
408
            {
409
            case 0xF5:
410
                byte = 0xA1;
411
                marker = 1;
412
                start_crc = rwptr + 1;
413
            break;
414
 
415
            case 0xF6:
416
                byte = 0xC2;
417
                marker = 1;
418
            break;
419
 
420
            case 0xF7:
421
                crc = wd93_crc(seldrive->t.trkd + start_crc, rwptr - start_crc);
422
                byte = crc & 0xFF;
423
            break;
424
            }
425
 
426
            seldrive->t.write(rwptr++, byte, marker);
427
            rwlen--;
428
            if (data == 0xF7)
429
            {
430
                seldrive->t.write(rwptr++, (crc >> 8) & 0xFF, 0);
431
                rwlen--; // second byte of CRC16
432
            }
433
 
434
            if ((int)rwlen > 0)
435
            {
436
               if (!conf.wd93_nodelay)
437
                   next += seldrive->t.ts_byte;
438
               state2 = S_WR_TRACK_DATA;
439
               state = S_WAIT;
440
               rqs = DRQ;
441
               status |= WDS_DRQ;
442
               break;
443
            }
444
            state = S_IDLE;
445
            break;
446
         }
447
 
448
         // ----------------------------------------------------
449
 
450
         case S_TYPE1_CMD: // Подана команда типа 1 (restore/seek/step)
451
            status &= ~(WDS_CRCERR | WDS_SEEKERR | WDS_WRITEP);
452
            rqs = 0;
453
 
454
            if (conf.trdos_wp[drive])
455
                status |= WDS_WRITEP;
456
 
457
            seldrive->motor = (cmd & CMD_SEEK_HEADLOAD) || (system & 0x20) ? next + 2*Z80FQ : 0;
458
 
459
            state2 = S_SEEKSTART; // default is seek/restore
460
 
461
            if (cmd & 0xE0)  // single step
462
            {
463
               if (cmd & 0x40) // step in / step out
464
                   stepdirection = (cmd & CMD_SEEK_DIR) ? -1 : 1;
465
               state2 = S_STEP;
466
            }
467
 
468
            next += (Z80FQ*14)/1000000;
469
            state = S_WAIT; // Задержка 14мкс перед появленеим статуса BUSY
470
         break;
471
 
472
 
473
         case S_STEP:
474
         {
475
            status |= WDS_BUSY;
476
            trdos_seek = ROMLED_TIME;
477
 
478
            if (seldrive->track == 0 && stepdirection < 0) // проверка TRK00
479
            {
480
                track = 0;
481
                state = S_VERIFY; // Обработка бита команды V
482
                break;
483
            }
484
 
485
            // Обработкабита T=1 (для seek всегда 1, для restore всегда 0, но обновление регистра трэка делается)
486
            if (!(cmd & 0xF0) || (cmd & CMD_SEEK_TRKUPD))
487
                track += stepdirection;
488
 
489
            if(seldrive->motor)
490
            {
491
                seldrive->track += stepdirection;
492
                if (seldrive->track == (unsigned char)-1)
493
                    seldrive->track = 0;
494
                if (seldrive->track >= MAX_PHYS_CYL)
495
                    seldrive->track = MAX_PHYS_CYL;
496
                seldrive->t.clear();
497
            }
498
 
499
            static const unsigned steps[] = { 6,12,20,30 };
500
            if (!conf.wd93_nodelay)
501
                next += steps[cmd & CMD_SEEK_RATE]*Z80FQ/1000;
502
 
503
            #ifndef MOD_9X
504
            if (!conf.wd93_nodelay && conf.fdd_noise)
505
                Beep((stepdirection > 0)? 600 : 800, 2);
506
            #endif
507
 
508
            state2 = (cmd & 0xE0) ? S_VERIFY /*Команда step*/: S_SEEK /*Команда seek/restore*/;
509
            state = S_WAIT;
510
            break;
511
         }
512
 
513
         case S_SEEKSTART:
514
            status |= WDS_BUSY;
515
 
516
            if (!(cmd & 0x10)) // Команда restore
517
            {
518
                if (!conf.wd93_nodelay)
519
                {
520
                    state2 = S_RESTORE;
521
                    next += (Z80FQ*21)/1000000; // задержка ~21мкс перед загрузкой регистра трэка
522
                    state = S_WAIT;
523
                    break;
524
                }
525
 
526
                state = S_RESTORE;
527
                break;
528
            }
529
            state = S_SEEK;
530
            break;
531
 
532
         case S_RESTORE:
533
            track = 0xFF;
534
            data = 0;
535
            state = S_SEEK;
536
            break;
537
 
538
         case S_SEEK:
539
            if (data == track)
540
            {
541
                state = S_VERIFY;
542
                break;
543
            }
544
            stepdirection = (data < track) ? -1 : 1;
545
            state = S_STEP;
546
            break;
547
 
548
         case S_VERIFY:
549
            if (!(cmd & CMD_SEEK_VERIFY)) // Проверка номера трэка не нужна V=0
550
            {
551
                status |= WDS_BUSY;
552
                state2 = S_IDLE;
553
                state = S_WAIT;
554
                idx_tmo = next + 15 * Z80FQ/FDD_RPS; // 15 disk turns
555
                next += (105*Z80FQ)/1000000; // Задержка 105мкс со статусом BUSY
556
                break;
557
            }
558
 
559
            // Проверка номера трэка нужна V=1
560
            sign_status |= SIG_HLD;
561
 
562
            // Ожидание 15мс
563
            //       |
564
            //       v
565
            // Ожидание HLT == 1
566
            //       |
567
            //       v
568
            // S_VERIFY2
569
            if (!conf.wd93_nodelay)
570
            {
571
                next += (15*Z80FQ)/1000; // Задержка 15мс
572
                state2 = S_WAIT_HLT;
573
                state = S_WAIT;
574
                break;
575
            }
576
            state = S_WAIT_HLT;
577
 
578
         case S_WAIT_HLT:
579
            if(!(system & 0x08)) // HLT = 0 (бесконечное ожидание HLT)
580
            {
581
                return;
582
            }
583
            state = S_VERIFY2;
584
 
585
         case S_VERIFY2:
586
            end_waiting_am = next + 6*Z80FQ/FDD_RPS; // max wait disk 6 turns
587
            load();
588
            find_marker();
589
            break;
590
 
591
         // ----------------------------------------------------
592
 
593
         case S_RESET: // seek to trk0, but don't be busy
594
            if (!seldrive->track)
595
                state = S_IDLE;
596
            else
597
            {
598
                seldrive->track--;
599
                seldrive->t.clear();
600
            }
601
            // if (!seldrive->track) track = 0;
602
            next += 6*Z80FQ/1000;
603
            break;
604
 
605
 
606
         default:
607
            errexit("WD1793 in wrong state");
608
      }
609
   }
610
}
611
 
612
void WD1793::find_marker()
613
{
614
   if (conf.wd93_nodelay && seldrive->track != track)
615
       seldrive->track = track;
616
   load();
617
 
618
   foundid = -1;
619
   if (seldrive->motor && seldrive->rawdata)
620
   {
621
      unsigned div = seldrive->t.trklen*seldrive->t.ts_byte; // Длина дорожки в тактах cpu
622
      unsigned i = (unsigned)((next+tshift) % div) / seldrive->t.ts_byte; // Позиция байта соответствующего текущему такту на дорожке
623
      unsigned wait = -1;
624
 
625
      // Поиск заголовка минимально отстоящего от текущего байта
626
      for (unsigned is = 0; is < seldrive->t.s; is++)
627
      {
628
         unsigned pos = seldrive->t.hdr[is].id - seldrive->t.trkd; // Смещение (в байтах) заголовка относительно начала дорожки
629
         unsigned dist = (pos > i)? pos-i : seldrive->t.trklen+pos-i; // Расстояние (в байтах) от заголовка до текущего байта
630
         if (dist < wait)
631
         {
632
             wait = dist;
633
             foundid = is;
634
         }
635
      }
636
 
637
      if (foundid != -1)
638
          wait *= seldrive->t.ts_byte; // Задержка в тактах от текущего такта до такта чтения первого байта заголовка
639
      else
640
          wait = 10*Z80FQ/FDD_RPS;
641
 
642
      if (conf.wd93_nodelay && foundid != -1)
643
      {
644
         // adjust tshift, that id appares right under head
645
         unsigned pos = seldrive->t.hdr[foundid].id - seldrive->t.trkd + 2;
646
         tshift = (unsigned)(((pos * seldrive->t.ts_byte) - (next % div) + div) % div);
647
         wait = 100; // delay=0 causes fdc to search infinitely, when no matched id on track
648
      }
649
 
650
      next += wait;
651
   } // else no index pulses - infinite wait
652
   else
653
   {
654
       next = comp.t_states + cpu.t + 1;
655
   }
656
 
657
   if (seldrive->rawdata && next > end_waiting_am)
658
   {
659
       next = end_waiting_am;
660
       foundid = -1;
661
   }
662
   state = S_WAIT;
663
   state2 = S_FOUND_NEXT_ID;
664
}
665
 
666
char WD1793::notready()
667
{
668
   // fdc is too fast in no-delay mode, wait until cpu handles DRQ, but not more 'end_waiting_am'
669
   if (conf.wd93_nodelay && (rqs & DRQ) && (next < (end_waiting_am - 5*Z80FQ/FDD_RPS) + (600*Z80FQ)/1000))
670
   {
671
       state2 = state;
672
       state = S_WAIT;
673
       next += seldrive->t.ts_byte;
674
       return 1;
675
   }
676
 
677
   return 0;
678
}
679
 
680
void WD1793::getindex()
681
{
682
   unsigned trlen = seldrive->t.trklen*seldrive->t.ts_byte;
683
   unsigned ticks = (unsigned)((next+tshift) % trlen);
684
   if (!conf.wd93_nodelay)
685
       next += (trlen - ticks);
686
   rwptr = 0;
687
   rwlen = seldrive->t.trklen;
688
   state = S_WAIT;
689
}
690
 
691
void WD1793::load()
692
{
693
   seldrive->t.seek(seldrive, seldrive->track, side, LOAD_SECTORS);
694
}
695
 
696
unsigned char WD1793::in(unsigned char port)
697
{
698
   process();
699
   if (port & 0x80)
700
       return rqs | (system & 0x3F);
701
   if (port == 0x1F)
702
   {
703
       rqs &= ~INTRQ;
704
       return RdStatus();
705
   }
706
   if (port == 0x3F)
707
       return track;
708
   if (port == 0x5F)
709
       return sector;
710
   if (port == 0x7F)
711
   {
712
       status &= ~WDS_DRQ;
713
       rqs &= ~DRQ;
714
       return data;
715
   }
716
   return 0xFF;
717
}
718
 
719
u8 WD1793::RdStatus()
720
{
721
    if(!(cmd & 0x80))
722
    {
723
        // hld & hlt
724
        return status | (((sign_status & SIG_HLD) && (system & 8)) ? WDS_HEADL : 0);
725
    }
726
    return status;
727
}
728
 
729
 
730
void WD1793::out(unsigned char port, unsigned char val)
731
{
732
   process();
733
 
734
   if (port == 0x1F)
735
   { // cmd
736
 
737
      // force interrupt (type 4)
738
      if ((val & 0xF0) == 0xD0)
739
      {
740
         u8 Cond = (val & 0xF);
741
         next = comp.t_states + cpu.t;
742
         idx_cnt = 0;
743
         idx_tmo = next + 15 * Z80FQ/FDD_RPS; // 15 disk turns
744
         cmd = val;
745
 
746
         if(Cond == 0)
747
         {
748
             state = S_IDLE; rqs = 0;
749
             status &= ~WDS_BUSY;
750
             return;
751
         }
752
 
753
         if(Cond & 8) // unconditional int
754
         {
755
             state = S_IDLE; rqs = INTRQ;
756
             status &= ~WDS_BUSY;
757
             return;
758
         }
759
 
760
         if(Cond & 4) // int by idam (unimplemented yet)
761
         {
762
             state = S_IDLE; rqs = INTRQ;
763
             status &= ~WDS_BUSY;
764
             return;
765
         }
766
 
767
         if(Cond & 2) // int 1->0 rdy (unimplemented yet)
768
         {
769
             state = S_IDLE; rqs = INTRQ;
770
             status &= ~WDS_BUSY;
771
             return;
772
         }
773
 
774
         if(Cond & 1) // int 0->1 rdy (unimplemented yet)
775
         {
776
             state = S_IDLE; rqs = INTRQ;
777
             status &= ~WDS_BUSY;
778
             return;
779
         }
780
 
781
         return;
782
      }
783
 
784
      if (status & WDS_BUSY)
785
          return;
786
      cmd = val;
787
      next = comp.t_states + cpu.t;
788
      status |= WDS_BUSY;
789
      rqs = 0;
790
      idx_cnt = 0;
791
      idx_tmo = LLONG_MAX;
792
 
793
      //-----------------------------------------------------------------------
794
 
795
      if (cmd & 0x80) // read/write command (type 2, 3)
796
      {
797
         status = (status | WDS_BUSY) & ~(WDS_DRQ | WDS_LOST | WDS_NOTFOUND | WDS_RECORDT | WDS_WRITEP);
798
 
799
         // continue disk spinning
800
         seldrive->motor = next + 2*Z80FQ;
801
 
802
         // abort if no disk
803
         if (status & WDS_NOTRDY)
804
         {
805
             state2 = S_IDLE;
806
             state = S_WAIT;
807
             next = comp.t_states + cpu.t + Z80FQ/FDD_RPS;
808
             rqs = INTRQ;
809
             return;
810
         }
811
 
812
         sign_status |= SIG_HLD;
813
 
814
         state = S_DELAY_BEFORE_CMD;
815
         return;
816
      }
817
 
818
      // (type 1)
819
      if(cmd & CMD_SEEK_HEADLOAD) // h = 1
820
          sign_status |= SIG_HLD;
821
      else
822
          sign_status &= ~SIG_HLD;
823
 
824
      // else seek/step command
825
      status &= ~WDS_BUSY;
826
      state = S_TYPE1_CMD;
827
      return;
828
   }
829
 
830
   //=======================================================================
831
 
832
   if (port == 0x3F)
833
   {
834
       track = val;
835
       return;
836
   }
837
 
838
   if (port == 0x5F)
839
   {
840
       sector = val;
841
       return;
842
   }
843
 
844
   if (port == 0x7F)
845
   {
846
       data = val;
847
       rqs &= ~DRQ;
848
       status &= ~WDS_DRQ;
849
       return;
850
   }
851
 
852
   if (port & 0x80) // FF
853
   { // system
854
      drive = val & 3;
855
      side = ~(val >> 4) & 1;
856
      seldrive = &fdd[drive];
857
      seldrive->t.clear();
858
 
859
      if (!(val & 0x04))
860
      { // reset
861
         status = WDS_NOTRDY;
862
         rqs = INTRQ;
863
         seldrive->motor = 0;
864
         state = S_IDLE;
865
         idx_cnt = 0;
866
 
867
         #if 1 // move head to trk00
868
//         steptime = 6 * (Z80FQ / 1000); // 6ms
869
         next += 1*Z80FQ/1000; // 1ms before command
870
         state = S_RESET;
871
           //seldrive->track = 0;
872
         #endif
873
      }
874
      else
875
      {
876
          if((system ^ val) & SYS_HLT) // hlt 0->1
877
          {
878
              if(!(status & WDS_BUSY))
879
              {
880
                  idx_cnt++;
881
              }
882
          }
883
      }
884
 
885
      if(val & 0x20) // В quorum бит D5 управляет мотором дисковода
886
      {
887
          sign_status |= SIG_HLD;
888
          seldrive->motor = next + 2*Z80FQ;
889
      }
890
      system = val;
891
   }
892
}
893
 
894
void WD1793::trdos_traps()
895
{
896
   unsigned pc = (cpu.pc & 0xFFFF);
897
   if (pc < 0x3DFD)
898
       return;
899
 
900
   // Позиционирование на соседнюю дорожку (пауза)
901
   if (pc == 0x3DFD && bankr[0][0x3DFD] == 0x3E && bankr[0][0x3DFF] == 0x0E)
902
   {
903
       cpu.pc = cpu.DbgMemIf->rm(cpu.sp++);
904
       cpu.pc |= (cpu.DbgMemIf->rm(cpu.sp++) << 8);
905
       cpu.a = 0;
906
       cpu.c = 0;
907
   }
908
 
909
   // Позиционирование на произвольную дорожку (пауза)
910
   if (pc == 0x3EA0 && bankr[0][0x3EA0] == 0x06 && bankr[0][0x3EA2] == 0x3E)
911
   {
912
       cpu.pc = cpu.DbgMemIf->rm(cpu.sp++);
913
       cpu.pc |= (cpu.DbgMemIf->rm(cpu.sp++) << 8);
914
       cpu.a = 0;
915
       cpu.b = 0;
916
   }
917
 
918
   if (pc == 0x3E01 && bankr[0][0x3E01] == 0x0D)
919
   {
920
       cpu.a = cpu.c = 1;
921
       return;
922
   } // no delays
923
 
924
   if (pc == 0x3FEC && bankr[0][0x3FED] == 0xA2 &&
925
              (state == S_READ || (state2 == S_READ && state == S_WAIT)))
926
   {
927
      trdos_load = ROMLED_TIME;
928
      if (rqs & DRQ)
929
      {
930
         cpu.DbgMemIf->wm(cpu.hl, data); // move byte from controller
931
         cpu.hl++;
932
         cpu.b--;
933
         rqs &= ~DRQ;
934
         status &= ~WDS_DRQ;
935
      }
936
 
937
      if(seldrive->t.trkd)
938
      {
939
          while (rwlen)
940
          { // move others
941
             cpu.DbgMemIf->wm(cpu.hl, seldrive->t.trkd[rwptr++]);
942
             rwlen--;
943
             cpu.hl++;
944
             cpu.b--;
945
          }
946
      }
947
      cpu.pc += 2; // skip INI
948
      return;
949
   }
950
   if (pc == 0x3FD1 && bankr[0][0x3FD2] == 0xA3 &&
951
              (rqs & DRQ) && (rwlen>1) && (state == S_WRITE || (state2 == S_WRITE && state == S_WAIT)))
952
   {
953
      trdos_save = ROMLED_TIME;
954
      while (rwlen > 1)
955
      {
956
         seldrive->t.write(rwptr++, cpu.DbgMemIf->rm(cpu.hl), 0);
957
         rwlen--;
958
         cpu.hl++;
959
         cpu.b--;
960
      }
961
      cpu.pc += 2; // skip OUTI
962
      return;
963
   }
964
}