OSDN Git Service

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