OSDN Git Service

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