OSDN Git Service

033687d0e2a3bc5409eca26c927372760071542e
[csp-qt/common_source_project-fm7.git] / source / src / vm / pc6001 / floppy.cpp
1 //
2 // PC-6001/6601 disk I/O
3 // This file is based on a disk I/O program in C++
4 // by Mr. Yumitaro and translated into C for Cocoa iP6
5 // by Koichi NISHIDA 2006
6 //
7
8 /*
9         NEC PC-6601 Emulator 'yaPC-6601'
10         NEC PC-6601SR Emulator 'yaPC-6801'
11
12         Author : tanam
13         Date   : 2013.12.04-
14
15         [ internal floppy drive ]
16 */
17
18 #include "floppy.h"
19 #include "../disk.h"
20 #include "../noise.h"
21
22 int FLOPPY::Seek88(int drvno, int trackno, int sectno)
23 {
24         if(drvno < 2) {
25                 if(cur_trk[drvno] != trackno) {
26                         if(d_noise_seek != NULL) d_noise_seek->play();
27                 }
28                 cur_trk[drvno] = trackno;
29                 cur_sct[drvno] = sectno;
30                 cur_pos[drvno] = 0;
31                 
32                 if(disk[drvno]->get_track(trackno >> 1, trackno & 1)) {
33                         for(int i = 0; i < disk[drvno]->sector_num.sd; i++) {
34                                 if(disk[drvno]->get_sector(trackno >> 1, 0/*trackno & 1*/, i)) {
35                                         if(disk[drvno]->id[2] == sectno) {
36                                                 return 1;
37                                         }
38                                 }
39                         }
40                 }
41         }
42         return 0;
43 }
44
45 unsigned char FLOPPY::Getc88(int drvno)
46 {
47         if(drvno < 2 && disk[drvno]->sector != NULL) {
48                 if(cur_pos[drvno] >= disk[drvno]->sector_size.sd) {
49                         cur_sct[drvno]++;
50                         if(!Seek88(drvno, cur_trk[drvno], cur_sct[drvno])) {
51 //                              cur_trk[drvno]++;
52                                 cur_trk[drvno] += 2;
53                                 cur_sct[drvno] = 1;
54                                 if(!Seek88(drvno, cur_trk[drvno], cur_sct[drvno])) {
55                                         return 0xff;
56                                 }
57                         }
58                 }
59                 access[drvno] = true;
60                 return disk[drvno]->sector[cur_pos[drvno]++];
61         }
62         return 0xff;
63 }
64
65 int FLOPPY::Putc88(int drvno, unsigned char dat)
66 {
67         if(drvno < 2 && disk[drvno]->sector != NULL) {
68                 if(cur_pos[drvno] >= disk[drvno]->sector_size.sd) {
69                         cur_sct[drvno]++;
70                         if(!Seek88(drvno, cur_trk[drvno], cur_sct[drvno])) {
71 //                              cur_trk[drvno]++;
72                                 cur_trk[drvno] += 2;
73                                 cur_sct[drvno] = 1;
74                                 if(!Seek88(drvno, cur_trk[drvno], cur_sct[drvno])) {
75                                         return 0xff;
76                                 }
77                         }
78                 }
79                 access[drvno] = true;
80                 disk[drvno]->sector[cur_pos[drvno]++] = dat;
81                 return 1;
82         }
83         return 0;
84 }
85
86 // push data to data buffer
87 void FLOPPY::Push(int part, unsigned char data)
88 {
89         if (part > 3) return;
90         
91         if(Index[part] < 256) Data[part][Index[part]++] = data;
92 }
93
94 // pop data from data buffer
95 unsigned char FLOPPY::Pop(int part)
96 {
97         if(part > 3) return 0xff;
98         
99         if(Index[part] > 0) return Data[part][--Index[part]];
100         else                return 0xff;
101 }
102
103 // clear data
104 void FLOPPY::Clear(int i)
105 {
106         Index[i] = 0;
107 }
108
109 // FDC Status
110 #define FDC_BUSY                        (0x10)
111 #define FDC_READY                       (0x00)
112 #define FDC_NON_DMA                     (0x20)
113 #define FDC_FD2PC                       (0x40)
114 #define FDC_PC2FD                       (0x00)
115 #define FDC_DATA_READY          (0x80)
116
117 // Result Status 0
118 #define ST0_NOT_READY           (0x08)
119 #define ST0_EQUIP_CHK           (0x10)
120 #define ST0_SEEK_END            (0x20)
121 #define ST0_IC_NT                       (0x00)
122 #define ST0_IC_AT                       (0x40)
123 #define ST0_IC_IC                       (0x80)
124 #define ST0_IC_AI                       (0xc0)
125
126 // Result Status 1
127 #define ST1_NOT_WRITABLE        (0x02)
128
129 // Result Status 2
130
131 // Result Status 3
132 #define ST3_TRACK0                      (0x10)
133 #define ST3_READY                       (0x20)
134 #define ST3_WRITE_PROTECT       (0x40)
135 #define ST3_FAULT                       (0x80)
136
137 // initialise
138 int FLOPPY::DiskInit66(void)
139 {
140         memset( &CmdIn,  0, sizeof( CmdBuffer ) );
141         memset( &CmdOut, 0, sizeof( CmdBuffer ) );
142         SeekST0 = 0;
143         LastCylinder = 0;
144         SeekEnd = 0;
145         SendSectors  = 0;
146         Status = FDC_DATA_READY | FDC_READY | FDC_PC2FD;
147         return 1;
148 }
149
150 // push data to status buffer
151 void FLOPPY::PushStatus(int data)
152 {
153         CmdOut.Data[CmdOut.Index++] = data;
154 }
155
156 // pop data from status buffer
157 unsigned char FLOPPY::PopStatus()
158 {
159         return CmdOut.Data[--CmdOut.Index];
160 }
161
162 // write to FDC
163 void FLOPPY::OutFDC(unsigned char data)
164 {
165         const int CmdLength[] = { 0,0,0,3,2,9,9,2,1,0,0,0,0,6,0,3 };
166         
167         CmdIn.Data[CmdIn.Index++] = data;
168         if (CmdLength[CmdIn.Data[0]&0xf] == CmdIn.Index) Exec();
169 }
170
171 // read from FDC
172 unsigned char FLOPPY::InFDC()
173 {
174         if (CmdOut.Index == 1) Status = FDC_DATA_READY | FDC_PC2FD;
175         return PopStatus();
176 }
177
178 // read
179 void FLOPPY::Read()
180 {
181         int Drv, C, H, R, N;
182         int i, j;
183         
184         Drv = CmdIn.Data[1]&3;          // drive number No.(0-3)
185         C   = CmdIn.Data[2];            // cylinder
186         H   = CmdIn.Data[3];            // head address
187         R   = CmdIn.Data[4];            // sector No.
188         N   = CmdIn.Data[5] ? CmdIn.Data[5]*256 : 256;  // sector size
189         
190         if (disk[Drv]->inserted) {
191                 // seek
192                 // double track number(1D->2D)
193                 Seek88(Drv, C*2+H, R);
194                 for (i = 0; i < SendSectors; i++) {
195                         Clear(i);
196                         for(j=0; j<N; j++)
197                                 Push(i, Getc88(Drv));
198                 }
199         }
200         PushStatus(N);  // N
201         PushStatus(R);  // R
202         PushStatus(H);  // H
203         PushStatus(C);  // C
204         PushStatus(0);  // st2
205         PushStatus(0);  // st1
206         PushStatus(disk[Drv]->inserted ? 0 : ST0_NOT_READY);    // st0  bit3 : media not ready
207         Status = FDC_DATA_READY | FDC_FD2PC;
208 }
209
210 // Write
211 void FLOPPY::Write(void)
212 {
213         int Drv, C, H, R, N;
214         int i, j;
215         
216         Drv = CmdIn.Data[1]&3;          // drive No.(0-3)
217         C   = CmdIn.Data[2];            // cylinder
218         H   = CmdIn.Data[3];            // head address
219         R   = CmdIn.Data[4];            // sector No.
220         N   = CmdIn.Data[5] ? CmdIn.Data[5]*256 : 256;  // sector size
221         
222         if (disk[Drv]->inserted) {
223                 // seek
224                 // double track number(1D->2D)
225                 Seek88(Drv, C*2+H, R);
226                 for (i=0; i<SendSectors; i++) {
227                         for(j=0; j<0x100; j++)
228                                 Putc88(Drv, Pop(i));    // write data
229                 }
230         }
231         
232         PushStatus(N);  // N
233         PushStatus(R);  // R
234         PushStatus(H);  // H
235         PushStatus(C);  // C
236         PushStatus(0);  // st2
237         PushStatus(0);  // st1
238         
239         PushStatus(disk[Drv]->inserted ? 0 : ST0_NOT_READY);    // st0  bit3 : media not ready
240         
241         Status = FDC_DATA_READY | FDC_FD2PC;
242 }
243
244 // seek
245 void FLOPPY::Seek(void)
246 {
247         int Drv,C,H;
248         
249         Drv = CmdIn.Data[1]&3;          // drive No.(0-3)
250         C   = CmdIn.Data[2];            // cylinder
251         H   = CmdIn.Data[3];            // head address
252         
253         if (!disk[Drv]->inserted) {     // disk unmounted ?
254                 SeekST0      = ST0_IC_AT | ST0_SEEK_END | ST0_NOT_READY | Drv;
255                 SeekEnd      = 0;
256                 LastCylinder = 0;
257         } else { // seek
258                 // double number(1D->2D)
259                 Seek88(Drv, C*2+H, 1);
260                 SeekST0      = ST0_IC_NT | ST0_SEEK_END | Drv;
261                 SeekEnd      = 1;
262                 LastCylinder = C;
263         }
264 }
265
266 // sense interrupt status
267 void FLOPPY::SenseInterruptStatus(void)
268 {
269         if (SeekEnd) {
270                 SeekEnd = 0;
271                 PushStatus(LastCylinder);
272                 PushStatus(SeekST0);
273         } else {
274                 PushStatus(0);
275                 PushStatus(ST0_IC_IC);
276         }
277         
278         Status = FDC_DATA_READY | FDC_FD2PC;
279 }
280
281 // execute FDC command
282 void FLOPPY::Exec()
283 {
284         CmdOut.Index = 0;
285         switch (CmdIn.Data[0] & 0xf) {
286         case 0x03:      // Specify
287                 break;
288         case 0x05:      // Write Data
289                 Write();
290                 break;
291         case 0x06:      // Read Data
292                 Read();
293                 break;
294         case 0x08:      // Sense Interrupt Status
295                 SenseInterruptStatus();
296                 break;
297         case 0x0d:      // Write ID
298                 // Format is Not Implimented
299                 break;
300         case 0x07:      // Recalibrate
301                 CmdIn.Data[2] = 0;      // Seek to TRACK0
302         case 0x0f:      // Seek
303                 Seek();
304                 break;
305         default: ;      // Invalid
306         }
307         CmdIn.Index = 0;
308 }
309
310 // I/O access functions
311 void FLOPPY::OutB1H_66(unsigned char data) { DIO = data&2 ? 1 : 0; }                    // FD mode
312 void FLOPPY::OutB2H_66(unsigned char data) {}                                                                   // FDC INT?
313 void FLOPPY::OutB3H_66(unsigned char data) {}                                                                   // in out of PortB2h
314 void FLOPPY::OutD0H_66(unsigned char data) { Push(0, data); }                                   // Buffer
315 void FLOPPY::OutD1H_66(unsigned char data) { Push(1, data); }                                   // Buffer
316 void FLOPPY::OutD2H_66(unsigned char data) { Push(2, data); }                                   // Buffer
317 void FLOPPY::OutD3H_66(unsigned char data) { Push(3, data); }                                   // Buffer
318 void FLOPPY::OutD6H_66(unsigned char data) {}                                                                   // select drive
319 void FLOPPY::OutD8H_66(unsigned char data) {}                                                                   //
320 void FLOPPY::OutDAH_66(unsigned char data) { SendSectors = ~(data - 0x10); }    // set transfer amount
321 void FLOPPY::OutDDH_66(unsigned char data) { OutFDC(data); }                                    // FDC data register
322 void FLOPPY::OutDEH_66(unsigned char data) {}                                                                   // ?
323         
324 unsigned char FLOPPY::InB2H_66() { return 3; }                                                                  // FDC INT
325 unsigned char FLOPPY::InD0H_66() { return Pop(0); }                                                             // Buffer
326 unsigned char FLOPPY::InD1H_66() { return Pop(1); }                                                             // Buffer
327 unsigned char FLOPPY::InD2H_66() { return Pop(2); }                                                             // Buffer
328 unsigned char FLOPPY::InD3H_66() { return Pop(3); }                                                             // Buffer
329 unsigned char FLOPPY::InD4H_66() { return 0; }                                                                  // Mortor(on 0/off 1)
330 unsigned char FLOPPY::InDCH_66() { return Status; }                                                             // FDC status register
331 unsigned char FLOPPY::InDDH_66() { return InFDC(); }                                                    // FDC data register
332
333 void FLOPPY::initialize()
334 {
335         for(int i = 0; i < 2; i++) {
336                 disk[i] = new DISK(emu);
337                 disk[i]->set_device_name(_T("%s/Disk #%d"), this_device_name, i + 1);
338                 disk[i]->drive_type = DRIVE_TYPE_2D;
339         }
340         if(d_noise_seek != NULL) {
341                 d_noise_seek->set_device_name(_T("Noise Player (FDD Seek)"));
342                 if(!d_noise_seek->load_wav_file(_T("FDDSEEK.WAV"))) {
343                         if(!d_noise_seek->load_wav_file(_T("FDDSEEK1.WAV"))) {
344                                 d_noise_seek->load_wav_file(_T("SEEK.WAV"));
345                         }
346                 }
347                 d_noise_seek->set_mute(!config.sound_noise_fdd);
348         }
349 //      if(d_noise_head_down != NULL) {
350 //              d_noise_head_down->set_device_name(_T("Noise Player (FDD Head Load)"));
351 //              d_noise_head_down->load_wav_file(_T("HEADDOWN.WAV"));
352 //              d_noise_head_down->set_mute(!config.sound_noise_fdd);
353 //      }
354 //      if(d_noise_head_up != NULL) {
355 //              d_noise_head_up->set_device_name(_T("Noise Player (FDD Head Unload)"));
356 //              d_noise_head_up->load_wav_file(_T("HEADUP.WAV"));
357 //              d_noise_head_up->set_mute(!config.sound_noise_fdd);
358 //      }
359         DiskInit66();
360 }
361
362 void FLOPPY::release()
363 {
364         for(int i = 0; i < 2; i++) {
365                 if(disk[i]) {
366                         disk[i]->close();
367                         delete disk[i];
368                 }
369         }
370 }
371
372 void FLOPPY::reset()
373 {
374         io_B1H = 0;
375         memset(Index, 0, sizeof(Index));
376 }
377
378 void FLOPPY::write_io8(uint32_t addr, uint32_t data)
379 {
380         // disk I/O
381         uint16_t port=(addr & 0x00ff);
382         uint8_t Value=(data & 0xff);
383         
384         switch(port)
385         {
386         // disk I/O
387         case 0xB1:
388         case 0xB5:
389                 io_B1H = Value;
390                 break;
391         case 0xB2:
392         case 0xB6:
393                 OutB2H_66(Value);
394                 break;
395         case 0xB3:
396         case 0xB7:
397                 OutB3H_66(Value);
398                 break;
399         case 0xD0:
400                 if(io_B1H & 4) {
401                         d_ext->write_io8(0, data);
402                 } else {
403                         OutD0H_66(Value);
404                 }
405                 break;
406         case 0xD1:
407                 if(io_B1H & 4) {
408                         d_ext->write_io8(1, data);
409                 } else {
410                         OutD1H_66(Value);
411                 }
412                 break;
413         case 0xD2:
414                 if(io_B1H & 4) {
415                         d_ext->write_io8(2, data);
416                 } else {
417                         OutD2H_66(Value);
418                 }
419                 break;
420         case 0xD3:
421                 if(io_B1H & 4) {
422                         d_ext->write_io8(3, data);
423                 } else {
424                         OutD3H_66(Value);
425                 }
426                 break;
427         case 0xD4:
428                 if(io_B1H & 4) {
429                         d_ext->write_io8(0, data);
430                 }
431                 break;
432         case 0xD5:
433                 if(io_B1H & 4) {
434                         d_ext->write_io8(1, data);
435                 }
436                 break;
437         case 0xD6:
438                 if(io_B1H & 4) {
439                         d_ext->write_io8(2, data);
440                 } else {
441                         OutD6H_66(Value);
442                 }
443                 break;
444         case 0xD7:
445                 if(io_B1H & 4) {
446                         d_ext->write_io8(3, data);
447                 }
448                 break;
449         case 0xD8:
450                 OutD8H_66(Value);
451                 break;
452         case 0xDA:
453                 OutDAH_66(Value);
454                 break;
455         case 0xDD:
456                 OutDDH_66(Value);
457                 break;
458         case 0xDE:
459                 OutDEH_66(Value);
460                 break;
461         }
462         return;
463 }
464
465 uint32_t FLOPPY::read_io8(uint32_t addr)
466 {
467         // disk I/O
468         uint16_t port=(addr & 0x00ff);
469         uint8_t Value=0xff;
470         
471         switch(addr & 0xff) {
472         case 0xB2:
473         case 0xB6:
474                 Value=InB2H_66();
475                 break;
476         case 0xD0:
477                 if(io_B1H & 4) {
478                         Value=d_ext->read_io8(0);
479                 } else {
480                         Value=InD0H_66();
481                 }
482                 break;
483         case 0xD1:
484                 if(io_B1H & 4) {
485                         Value=d_ext->read_io8(1);
486                 } else {
487                         Value=InD1H_66();
488                 }
489                 break;
490         case 0xD2:
491                 if(io_B1H & 4) {
492                         Value=d_ext->read_io8(2);
493                 } else {
494                         Value=InD2H_66();
495                 }
496                 break;
497         case 0xD3:
498                 if(io_B1H & 4) {
499                         Value=d_ext->read_io8(3);
500                 } else {
501                         Value=InD3H_66();
502                 }
503                 break;
504         case 0xD4:
505                 if(io_B1H & 4) {
506                         Value=d_ext->read_io8(0);
507                 } else {
508                         Value=InD4H_66();
509                 }
510                 break;
511         case 0xD5:
512                 if(io_B1H & 4) {
513                         Value=d_ext->read_io8(1);
514                 }
515                 break;
516         case 0xD6:
517                 if(io_B1H & 4) {
518                         Value=d_ext->read_io8(2);
519                 }
520                 break;
521         case 0xD7:
522                 if(io_B1H & 4) {
523                         Value=d_ext->read_io8(3);
524                 }
525                 break;
526         case 0xDC:
527                 Value=InDCH_66();
528                 break;
529         case 0xDD:
530                 Value=InDDH_66();
531                 break;
532         }
533         return(Value);
534 }
535
536 uint32_t FLOPPY::read_signal(int ch)
537 {
538         // get access status
539         uint32_t stat = 0;
540         for(int drv = 0; drv < 2; drv++) {
541                 if(access[drv]) {
542                         stat |= 1 << drv;
543                 }
544                 access[drv] = false;
545         }
546         return stat;
547 }
548
549 void FLOPPY::open_disk(int drv, const _TCHAR* file_path, int bank)
550 {
551         if(drv < 2) {
552                 disk[drv]->open(file_path, bank);
553                 Seek88(drv, 0, 1);
554         }
555 }
556
557 void FLOPPY::close_disk(int drv)
558 {
559         if(drv < 2 && disk[drv]->inserted) {
560                 disk[drv]->close();
561         }
562 }
563
564 bool FLOPPY::is_disk_inserted(int drv)
565 {
566         if(drv < 2) {
567                 return disk[drv]->inserted;
568         }
569         return false;
570 }
571
572 void FLOPPY::is_disk_protected(int drv, bool value)
573 {
574         if(drv < 2) {
575                 disk[drv]->write_protected = value;
576         }
577 }
578
579 bool FLOPPY::is_disk_protected(int drv)
580 {
581         if(drv < 2) {
582                 return disk[drv]->write_protected;
583         }
584         return false;
585 }
586
587 void FLOPPY::update_config()
588 {
589         if(d_noise_seek != NULL) {
590                 d_noise_seek->set_mute(!config.sound_noise_fdd);
591         }
592 //      if(d_noise_head_down != NULL) {
593 //              d_noise_head_down->set_mute(!config.sound_noise_fdd);
594 //      }
595 //      if(d_noise_head_up != NULL) {
596 //              d_noise_head_up->set_mute(!config.sound_noise_fdd);
597 //      }
598 }
599
600 #define STATE_VERSION   1
601
602 bool FLOPPY::process_state(FILEIO* state_fio, bool loading)
603 {
604         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
605                 return false;
606         }
607         if(!state_fio->StateCheckInt32(this_device_id)) {
608                 return false;
609         }
610         state_fio->StateUint8(io_B1H);
611         for(int i = 0; i < 2; i++) {
612                 if(!disk[i]->process_state(state_fio, loading)) {
613                         return false;
614                 }
615         }
616         //state_fio->StateBuffer(cur_trk, sizeof(cur_trk), 1);
617         for(int i = 0; i < (sizeof(cur_trk) / sizeof(int)); i++) {
618                 state_fio->StateInt32(cur_trk[i]);
619         }
620         //state_fio->StateBuffer(cur_sct, sizeof(cur_sct), 1);
621         for(int i = 0; i < (sizeof(cur_sct) / sizeof(int)); i++) {
622                 state_fio->StateInt32(cur_sct[i]);
623         }
624         //state_fio->StateBuffer(cur_pos, sizeof(cur_pos), 1);
625         for(int i = 0; i < (sizeof(cur_pos) / sizeof(int)); i++) {
626                 state_fio->StateInt32(cur_pos[i]);
627         }
628         //state_fio->StateBuffer(access, sizeof(access), 1);
629         for(int i = 0; i < (sizeof(access) / sizeof(bool)); i++) {
630                 state_fio->StateBool(access[i]);
631         }
632         state_fio->StateBuffer(Data, sizeof(Data), 1);
633         //state_fio->StateBuffer(Index, sizeof(Index), 1);
634         for(int i = 0; i < (sizeof(Index) / sizeof(int)); i++) {
635                 state_fio->StateInt32(Index[i]);
636         }
637         //state_fio->StateBuffer(&CmdIn, sizeof(CmdBuffer), 1);
638         {
639                 state_fio->StateBuffer(CmdIn.Data, sizeof(CmdIn.Data), 1);
640                 state_fio->StateInt32(CmdIn.Index);
641         }
642         //state_fio->StateBuffer(&CmdOut, sizeof(CmdBuffer), 1);
643         {
644                 state_fio->StateBuffer(CmdOut.Data, sizeof(CmdOut.Data), 1);
645                 state_fio->StateInt32(CmdOut.Index);
646         }
647         state_fio->StateUint8(SeekST0);
648         state_fio->StateUint8(LastCylinder);
649         state_fio->StateInt32(SeekEnd);
650         state_fio->StateUint8(SendSectors);
651         state_fio->StateInt32(DIO);
652         state_fio->StateUint8(Status);
653         return true;
654 }