OSDN Git Service

[General] Merge upstream 2015-01-31 , pc8801ma is still not working correct.
[csp-qt/common_source_project-fm7.git] / source / src / vm / pc6031.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         Skelton for retropc emulator
10
11         Author : Takeda.Toshiya
12         Origin : tanam
13         Date   : 2014.05.21-
14
15         [ PC-6031 ]
16 */
17
18 #include "pc6031.h"
19 #include "disk.h"
20 #include "../fileio.h"
21
22 int PC6031::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.sd; 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 PC6031::Getc88(int drvno)
43 {
44         if(drvno < 2 && disk[drvno]->sector != NULL) {
45                 if(cur_pos[drvno] >= disk[drvno]->sector_size.sd) {
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 PC6031::Putc88(int drvno, unsigned char dat)
63 {
64         if(drvno < 2 && disk[drvno]->sector != NULL) {
65                 if(cur_pos[drvno] >= disk[drvno]->sector_size.sd) {
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 // command
84 enum FddCommand
85 {
86         INIT                            = 0x00,
87         WRITE_DATA                      = 0x01,
88         READ_DATA                       = 0x02,
89         SEND_DATA                       = 0x03,
90         COPY                            = 0x04,
91         FORMAT                          = 0x05,
92         SEND_RESULT_STATUS      = 0x06,
93         SEND_DRIVE_STATUS       = 0x07,
94         TRANSMIT                        = 0x11,
95         RECEIVE                         = 0x12,
96         LOAD                            = 0x14,
97         SAVE                            = 0x15,
98         WAIT                            = 0xff, // waiting state
99         EndofFdcCmd
100 };
101
102 // data input (port D0H)
103 unsigned char PC6031::FddIn60()
104 {
105         unsigned char ret;
106
107         if (mdisk.DAV) {                // if data is valid
108                 if (mdisk.step == 6) {
109                         mdisk.retdat = Getc88(mdisk.drv);
110                         if(--mdisk.size == 0) mdisk.step = 0;
111                 }
112                 mdisk.DAC = 1;
113                 ret = mdisk.retdat;
114         } else {                        // if data is not valid
115                 ret = 0xff;
116         }
117         return ret;
118 }
119
120 // data/command output (port D1H)
121 void PC6031::FddOut60(unsigned char dat)
122 {
123         if (mdisk.command == WAIT) {    // when command
124                 mdisk.command = dat;
125                 switch (mdisk.command) {
126                 case INIT:                                      // 00h init
127                         break;
128                 case WRITE_DATA:                        // 01h write data
129                         mdisk.step = 1;
130                         break;
131                 case READ_DATA:                         // 02h read data
132                         mdisk.step = 1;
133                         break;
134                 case SEND_DATA:                         // 03h send data
135                         mdisk.step = 6;
136                         break;
137                 case COPY:                                      // 04h copy
138                         break;
139                 case FORMAT:                            // 05h format
140                         break;
141                 case SEND_RESULT_STATUS:        // 06h send result status
142                         mdisk.retdat = 0x40;
143                         break;
144                 case SEND_DRIVE_STATUS:         // 07h send drive status
145                         mdisk.retdat |= 0x0a;
146                         break;
147                 case TRANSMIT:                          // 11h transnmit
148                         break;
149                 case RECEIVE:                           // 12h receive
150                         break;
151                 case LOAD:                                      // 14h load
152                         break;
153                 case SAVE:                                      // 15h save
154                         break;
155                 }
156         } else {                                        // when data
157                 switch (mdisk.command) {
158                 case WRITE_DATA:                        // 01h write data
159                         switch (mdisk.step) {
160                         case 1: // 01h:block number
161                                 mdisk.blk = dat;
162                                 mdisk.size = mdisk.blk*256;
163                                 mdisk.step++;
164                                 break;
165                         case 2: // 02h:drive number - 1
166                                 mdisk.drv = dat;
167                                 mdisk.step++;
168                                 break;
169                         case 3: // 03h:track number
170                                 mdisk.trk = dat;
171                                 mdisk.step++;
172                                 break;
173                         case 4: // 04h:sector number
174                                 mdisk.sct = dat;
175                                 // double track number(1D->2D)
176                                 Seek88(mdisk.drv, mdisk.trk*2, mdisk.sct);
177                                 mdisk.step++;
178                                 break;
179                         case 5: // 05h:write data
180                                 Putc88(mdisk.drv, dat);
181                                 if( --mdisk.size == 0 ){
182                                         mdisk.step = 0;
183                                 }
184                                 break;
185                         }
186                         break;
187                 case READ_DATA:                         // 02h read data
188                         switch (mdisk.step) {
189                         case 1: // 01h:block number
190                                 mdisk.blk = dat;
191                                 mdisk.size = mdisk.blk*256;
192                                 mdisk.step++;
193                                 break;
194                         case 2: // 02h:drive number-1
195                                 mdisk.drv = dat;
196                                 mdisk.step++;
197                                 break;
198                         case 3: // 03h:track number
199                                 mdisk.trk = dat;
200                                 mdisk.step++;
201                                 break;
202                         case 4: // 04h:sector number
203                                 mdisk.sct = dat;
204                                 // double track number(1D->2D)
205                                 Seek88(mdisk.drv, mdisk.trk*2, mdisk.sct);
206                                 mdisk.step = 0;
207                                 break;
208                         }
209                 }
210         }
211 }
212
213 // control input from disk unit (port D2H)
214 unsigned char PC6031::FddCntIn60(void)
215 {
216         if (((old_D2H & 0x01) ^ mdisk.DAV) || mdisk.RFD && mdisk.DAV) {
217                 mdisk.DAC = mdisk.DAV;
218         } else if (mdisk.ATN) {
219                 mdisk.RFD = 1;
220                 mdisk.command = WAIT;
221         } else if (mdisk.DAC) {
222                 mdisk.DAV = 0;
223         } else if (mdisk.RFD) {
224                 mdisk.DAV = 1;
225         }       
226         old_D2H = io_D2H;
227         io_D2H = 0xf0 | 0x08 /* (mdisk.ATN<<3) */ | (mdisk.DAC<<2) | (mdisk.RFD<<1) | mdisk.DAV;
228         return (io_D2H);
229 }
230
231 // control output to disk unit (port D3H)
232 void PC6031::FddCntOut60(unsigned char dat)
233 {
234         // 8255 basic behavior
235         if (!(dat&0x80)) {              // check msb
236                                                         // ignore when 1
237                 switch ((dat>>1)&0x07) {
238                 case 7: // bit7 ATN
239                         mdisk.ATN = dat&1;
240                         break;
241                 case 6: // bit6 DAC
242                         mdisk.DAC = dat&1;
243                         break;
244                 case 5: // bit5 RFD
245                         mdisk.RFD = dat&1;
246                         break;
247                 case 4: // bit4 DAV
248                         mdisk.DAV = dat&1;
249                         break;
250                 }
251                 io_D2H = 0xf0 | 0x08 /* (mdisk.ATN<<3) */ | (mdisk.DAC<<2) | (mdisk.RFD<<1) | mdisk.DAV;
252         }
253 }
254
255 // I/O access functions
256 void PC6031::OutD1H_60(unsigned char data) { io_D1H = data; FddOut60(io_D1H); }
257 void PC6031::OutD2H_60(unsigned char data) {
258         mdisk.ATN = (data & 0x80) >> 7;
259         mdisk.DAC = (data & 0x40) >> 6;
260         mdisk.RFD = (data & 0x20) >> 5;
261         mdisk.DAV = (data & 0x10) >> 4;
262         io_D2H = 0xf0 | 0x08 /* (mdisk.ATN<<3) */ | (mdisk.DAC<<2) | (mdisk.RFD<<1) | mdisk.DAV;
263 }
264 void PC6031::OutD3H_60(unsigned char data) { io_D3H = data; FddCntOut60(io_D3H); }
265
266 unsigned char PC6031::InD0H_60() { return FddIn60(); }
267 unsigned char PC6031::InD1H_60() { return io_D1H; }
268 unsigned char PC6031::InD2H_60() { io_D2H = FddCntIn60(); return io_D2H; }
269 unsigned char PC6031::InD3H_60() { return io_D3H; }
270
271 void PC6031::initialize()
272 {
273         for(int i = 0; i < 2; i++) {
274                 disk[i] = new DISK(emu);
275         }
276         DrvNum = 1;
277         memset(&mdisk, 0, sizeof(DISK60));
278         mdisk.command = WAIT;           // received command
279         mdisk.retdat  = 0xff;           // data from port D0H
280         io_D1H = 0;
281         io_D2H = 0xf0 | 0x08 /* (mdisk.ATN<<3) */ | (mdisk.DAC<<2) | (mdisk.RFD<<1) | mdisk.DAV;
282         io_D3H = 0;
283         old_D2H = 0;
284 }
285
286 void PC6031::release()
287 {
288         for(int i = 0; i < 2; i++) {
289                 if(disk[i]) {
290                         disk[i]->close();
291                         delete disk[i];
292                 }
293         }
294 }
295
296 void PC6031::write_io8(uint32 addr, uint32 data)
297 {
298         switch(addr & 3) {
299         case 1:
300                 OutD1H_60(data);
301                 break;
302         case 2:
303                 OutD2H_60(data);
304                 break;
305         case 3:
306                 OutD3H_60(data);
307                 break;
308         }
309 }
310
311 uint32 PC6031::read_io8(uint32 addr)
312 {
313         switch(addr & 3) {
314         case 0:
315                 return InD0H_60(); break;
316         case 1:
317                 return InD1H_60(); break;
318         case 2:
319                 return InD2H_60(); break;
320         case 3:
321                 return InD3H_60(); break;
322         }
323         return 0xff;
324 }
325
326 uint32 PC6031::read_signal(int ch)
327 {
328         // get access status
329         uint32 stat = 0;
330         for(int drv = 0; drv < 2; drv++) {
331                 if(access[drv]) {
332                         stat |= 1 << drv;
333                 }
334                 access[drv] = false;
335         }
336         return stat;
337 }
338
339 // ----------------------------------------------------------------------------
340 // user interface
341 // ----------------------------------------------------------------------------
342
343 void PC6031::open_disk(int drv, _TCHAR path[], int bank)
344 {
345         if(drv < 2) {
346                 disk[drv]->open(path, bank);
347                 Seek88(drv, 0, 1);
348         }
349 }
350
351 void PC6031::close_disk(int drv)
352 {
353         if(drv < 2 && disk[drv]->inserted) {
354                 disk[drv]->close();
355         }
356 }
357
358 bool PC6031::disk_inserted(int drv)
359 {
360         if(drv < 2) {
361                 return disk[drv]->inserted;
362         }
363         return false;
364 }
365
366 bool PC6031::disk_ejected(int drv)
367 {
368         if(drv < 2) {
369                 return disk[drv]->ejected;
370         }
371         return false;
372 }
373
374 #define STATE_VERSION   1
375
376 void PC6031::save_state(FILEIO* state_fio)
377 {
378         state_fio->FputUint32(STATE_VERSION);
379         state_fio->FputInt32(this_device_id);
380         
381         for(int i = 0; i < 2; i++) {
382                 disk[i]->save_state(state_fio);
383         }
384         state_fio->Fwrite(cur_trk, sizeof(cur_trk), 1);
385         state_fio->Fwrite(cur_sct, sizeof(cur_sct), 1);
386         state_fio->Fwrite(cur_pos, sizeof(cur_pos), 1);
387         state_fio->Fwrite(access, sizeof(access), 1);
388         state_fio->Fwrite(&mdisk, sizeof(DISK60), 1);
389         state_fio->FputUint8(io_D1H);
390         state_fio->FputUint8(io_D2H);
391         state_fio->FputUint8(old_D2H);
392         state_fio->FputUint8(io_D3H);
393         state_fio->FputInt32(DrvNum);
394 }
395
396 bool PC6031::load_state(FILEIO* state_fio)
397 {
398         if(state_fio->FgetUint32() != STATE_VERSION) {
399                 return false;
400         }
401         if(state_fio->FgetInt32() != this_device_id) {
402                 return false;
403         }
404         for(int i = 0; i < 2; i++) {
405                 if(!disk[i]->load_state(state_fio)) {
406                         return false;
407                 }
408         }
409         state_fio->Fread(cur_trk, sizeof(cur_trk), 1);
410         state_fio->Fread(cur_sct, sizeof(cur_sct), 1);
411         state_fio->Fread(cur_pos, sizeof(cur_pos), 1);
412         state_fio->Fread(access, sizeof(access), 1);
413         state_fio->Fread(&mdisk, sizeof(DISK60), 1);
414         io_D1H = state_fio->FgetUint8();
415         io_D2H = state_fio->FgetUint8();
416         old_D2H = state_fio->FgetUint8();
417         io_D3H = state_fio->FgetUint8();
418         DrvNum = state_fio->FgetInt32();
419         return true;
420 }
421