OSDN Git Service

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