OSDN Git Service

[VM][WIP] Apply some devices merging upstream 2018-10-05.This still not build.WIP.
[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 "noise.h"
21
22 int PC6031::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 PC6031::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 PC6031::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 // command
87 enum FddCommand
88 {
89         INIT                            = 0x00,
90         WRITE_DATA                      = 0x01,
91         READ_DATA                       = 0x02,
92         SEND_DATA                       = 0x03,
93         COPY                            = 0x04,
94         FORMAT                          = 0x05,
95         SEND_RESULT_STATUS      = 0x06,
96         SEND_DRIVE_STATUS       = 0x07,
97         TRANSMIT                        = 0x11,
98         RECEIVE                         = 0x12,
99         LOAD                            = 0x14,
100         SAVE                            = 0x15,
101         WAIT                            = 0xff, // waiting state
102         EndofFdcCmd
103 };
104
105 // data input (port D0H)
106 unsigned char PC6031::FddIn60()
107 {
108         unsigned char ret;
109
110         if (mdisk.DAV) {                // if data is valid
111                 if (mdisk.step == 6) {
112                         mdisk.retdat = Getc88(mdisk.drv);
113                         if(--mdisk.size == 0) mdisk.step = 0;
114                 }
115                 mdisk.DAC = 1;
116                 ret = mdisk.retdat;
117         } else {                        // if data is not valid
118                 ret = 0xff;
119         }
120         return ret;
121 }
122
123 // data/command output (port D1H)
124 void PC6031::FddOut60(unsigned char dat)
125 {
126         if (mdisk.command == WAIT) {    // when command
127                 mdisk.command = dat;
128                 switch (mdisk.command) {
129                 case INIT:                                      // 00h init
130                         break;
131                 case WRITE_DATA:                        // 01h write data
132                         mdisk.step = 1;
133                         break;
134                 case READ_DATA:                         // 02h read data
135                         mdisk.step = 1;
136                         break;
137                 case SEND_DATA:                         // 03h send data
138                         mdisk.step = 6;
139                         break;
140                 case COPY:                                      // 04h copy
141                         break;
142                 case FORMAT:                            // 05h format
143                         break;
144                 case SEND_RESULT_STATUS:        // 06h send result status
145                         mdisk.retdat = 0x40;
146                         break;
147                 case SEND_DRIVE_STATUS:         // 07h send drive status
148                         mdisk.retdat |= 0x0a;
149                         break;
150                 case TRANSMIT:                          // 11h transnmit
151                         break;
152                 case RECEIVE:                           // 12h receive
153                         break;
154                 case LOAD:                                      // 14h load
155                         break;
156                 case SAVE:                                      // 15h save
157                         break;
158                 }
159         } else {                                        // when data
160                 switch (mdisk.command) {
161                 case WRITE_DATA:                        // 01h write data
162                         switch (mdisk.step) {
163                         case 1: // 01h:block number
164                                 mdisk.blk = dat;
165                                 mdisk.size = mdisk.blk*256;
166                                 mdisk.step++;
167                                 break;
168                         case 2: // 02h:drive number - 1
169                                 mdisk.drv = dat;
170                                 mdisk.step++;
171                                 break;
172                         case 3: // 03h:track number
173                                 mdisk.trk = dat;
174                                 mdisk.step++;
175                                 break;
176                         case 4: // 04h:sector number
177                                 mdisk.sct = dat;
178                                 // double track number(1D->2D)
179                                 Seek88(mdisk.drv, mdisk.trk*2, mdisk.sct);
180                                 mdisk.step++;
181                                 break;
182                         case 5: // 05h:write data
183                                 Putc88(mdisk.drv, dat);
184                                 if( --mdisk.size == 0 ){
185                                         mdisk.step = 0;
186                                 }
187                                 break;
188                         }
189                         break;
190                 case READ_DATA:                         // 02h read data
191                         switch (mdisk.step) {
192                         case 1: // 01h:block number
193                                 mdisk.blk = dat;
194                                 mdisk.size = mdisk.blk*256;
195                                 mdisk.step++;
196                                 break;
197                         case 2: // 02h:drive number-1
198                                 mdisk.drv = dat;
199                                 mdisk.step++;
200                                 break;
201                         case 3: // 03h:track number
202                                 mdisk.trk = dat;
203                                 mdisk.step++;
204                                 break;
205                         case 4: // 04h:sector number
206                                 mdisk.sct = dat;
207                                 // double track number(1D->2D)
208                                 Seek88(mdisk.drv, mdisk.trk*2, mdisk.sct);
209                                 mdisk.step = 0;
210                                 break;
211                         }
212                 }
213         }
214 }
215
216 // control input from disk unit (port D2H)
217 unsigned char PC6031::FddCntIn60(void)
218 {
219         if ((((old_D2H & 0x01) ^ mdisk.DAV) != 0) || (mdisk.RFD != 0) && (mdisk.DAV != 0)) {  // ToDo: Check Logic 20180614 K.O
220                 mdisk.DAC = mdisk.DAV;
221         } else if (mdisk.ATN != 0) {
222                 mdisk.RFD = 1;
223                 mdisk.command = WAIT;
224         } else if (mdisk.DAC != 0) {
225                 mdisk.DAV = 0;
226         } else if (mdisk.RFD != 0) {
227                 mdisk.DAV = 1;
228         }       
229         old_D2H = io_D2H;
230         io_D2H = 0xf0 | 0x08 /* (mdisk.ATN<<3) */ | (mdisk.DAC<<2) | (mdisk.RFD<<1) | mdisk.DAV;
231         return (io_D2H);
232 }
233
234 // control output to disk unit (port D3H)
235 void PC6031::FddCntOut60(unsigned char dat)
236 {
237         // 8255 basic behavior
238         if (!(dat&0x80)) {              // check msb
239                                                         // ignore when 1
240                 switch ((dat>>1)&0x07) {
241                 case 7: // bit7 ATN
242                         mdisk.ATN = dat&1;
243                         break;
244                 case 6: // bit6 DAC
245                         mdisk.DAC = dat&1;
246                         break;
247                 case 5: // bit5 RFD
248                         mdisk.RFD = dat&1;
249                         break;
250                 case 4: // bit4 DAV
251                         mdisk.DAV = dat&1;
252                         break;
253                 }
254                 io_D2H = 0xf0 | 0x08 /* (mdisk.ATN<<3) */ | (mdisk.DAC<<2) | (mdisk.RFD<<1) | mdisk.DAV;
255         }
256 }
257
258 // I/O access functions
259 void PC6031::OutD1H_60(unsigned char data) { io_D1H = data; FddOut60(io_D1H); }
260 void PC6031::OutD2H_60(unsigned char data) {
261         mdisk.ATN = (data & 0x80) >> 7;
262         mdisk.DAC = (data & 0x40) >> 6;
263         mdisk.RFD = (data & 0x20) >> 5;
264         mdisk.DAV = (data & 0x10) >> 4;
265         io_D2H = 0xf0 | 0x08 /* (mdisk.ATN<<3) */ | (mdisk.DAC<<2) | (mdisk.RFD<<1) | mdisk.DAV;
266 }
267 void PC6031::OutD3H_60(unsigned char data) { io_D3H = data; FddCntOut60(io_D3H); }
268
269 unsigned char PC6031::InD0H_60() { return FddIn60(); }
270 unsigned char PC6031::InD1H_60() { return io_D1H; }
271 unsigned char PC6031::InD2H_60() { io_D2H = FddCntIn60(); return io_D2H; }
272 unsigned char PC6031::InD3H_60() { return io_D3H; }
273
274 void PC6031::initialize()
275 {
276         for(int i = 0; i < 2; i++) {
277                 disk[i] = new DISK(emu);
278                 disk[i]->set_device_name(_T("%s/Disk #%d"), this_device_name, i + 1);
279                 disk[i]->drive_type = DRIVE_TYPE_2D;
280         }
281         if(d_noise_seek != NULL) {
282                 d_noise_seek->set_device_name(_T("Noise Player (FDD Seek)"));
283                 if(!d_noise_seek->load_wav_file(_T("FDDSEEK.WAV"))) {
284                         if(!d_noise_seek->load_wav_file(_T("FDDSEEK1.WAV"))) {
285                                 d_noise_seek->load_wav_file(_T("SEEK.WAV"));
286                         }
287                 }
288                 d_noise_seek->set_mute(!config.sound_noise_fdd);
289         }
290 //      if(d_noise_head_down != NULL) {
291 //              d_noise_head_down->set_device_name(_T("Noise Player (FDD Head Load)"));
292 //              d_noise_head_down->load_wav_file(_T("HEADDOWN.WAV"));
293 //              d_noise_head_down->set_mute(!config.sound_noise_fdd);
294 //      }
295 //      if(d_noise_head_up != NULL) {
296 //              d_noise_head_up->set_device_name(_T("Noise Player (FDD Head Unload)"));
297 //              d_noise_head_up->load_wav_file(_T("HEADUP.WAV"));
298 //              d_noise_head_up->set_mute(!config.sound_noise_fdd);
299 //      }
300         DrvNum = 1;
301         memset(&mdisk, 0, sizeof(DISK60));
302         mdisk.command = WAIT;           // received command
303         mdisk.retdat  = 0xff;           // data from port D0H
304         io_D1H = 0;
305         io_D2H = 0xf0 | 0x08 /* (mdisk.ATN<<3) */ | (mdisk.DAC<<2) | (mdisk.RFD<<1) | mdisk.DAV;
306         io_D3H = 0;
307         old_D2H = 0;
308 }
309
310 void PC6031::release()
311 {
312         for(int i = 0; i < 2; i++) {
313                 if(disk[i]) {
314                         disk[i]->close();
315                         delete disk[i];
316                 }
317         }
318 }
319
320 void PC6031::write_io8(uint32_t addr, uint32_t data)
321 {
322         switch(addr & 3) {
323         case 1:
324                 OutD1H_60(data);
325                 break;
326         case 2:
327                 OutD2H_60(data);
328                 break;
329         case 3:
330                 OutD3H_60(data);
331                 break;
332         }
333 }
334
335 uint32_t PC6031::read_io8(uint32_t addr)
336 {
337         switch(addr & 3) {
338         case 0:
339                 return InD0H_60(); break;
340         case 1:
341                 return InD1H_60(); break;
342         case 2:
343                 return InD2H_60(); break;
344         case 3:
345                 return InD3H_60(); break;
346         }
347         return 0xff;
348 }
349
350 uint32_t PC6031::read_signal(int ch)
351 {
352         // get access status
353         uint32_t stat = 0;
354         for(int drv = 0; drv < 2; drv++) {
355                 if(access[drv]) {
356                         stat |= 1 << drv;
357                 }
358                 access[drv] = false;
359         }
360         return stat;
361 }
362
363 // ----------------------------------------------------------------------------
364 // user interface
365 // ----------------------------------------------------------------------------
366
367 void PC6031::open_disk(int drv, const _TCHAR* file_path, int bank)
368 {
369         if(drv < 2) {
370                 disk[drv]->open(file_path, bank);
371                 Seek88(drv, 0, 1);
372         }
373 }
374
375 void PC6031::close_disk(int drv)
376 {
377         if(drv < 2 && disk[drv]->inserted) {
378                 disk[drv]->close();
379         }
380 }
381
382 bool PC6031::is_disk_inserted(int drv)
383 {
384         if(drv < 2) {
385                 return disk[drv]->inserted;
386         }
387         return false;
388 }
389
390 bool PC6031::disk_ejected(int drv)
391 {
392         if(drv < 2) {
393                 return disk[drv]->ejected;
394         }
395         return false;
396 }
397
398 void PC6031::is_disk_protected(int drv, bool value)
399 {
400         if(drv < 2) {
401                 disk[drv]->write_protected = value;
402         }
403 }
404
405 bool PC6031::is_disk_protected(int drv)
406 {
407         if(drv < 2) {
408                 return disk[drv]->write_protected;
409         }
410         return false;
411 }
412
413 void PC6031::update_config()
414 {
415         if(d_noise_seek != NULL) {
416                 d_noise_seek->set_mute(!config.sound_noise_fdd);
417         }
418 //      if(d_noise_head_down != NULL) {
419 //              d_noise_head_down->set_mute(!config.sound_noise_fdd);
420 //      }
421 //      if(d_noise_head_up != NULL) {
422 //              d_noise_head_up->set_mute(!config.sound_noise_fdd);
423 //      }
424 }
425
426 #define STATE_VERSION   1
427
428 bool PC6031::process_state(FILEIO* state_fio, bool loading)
429 {
430         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
431                 return false;
432         }
433         if(!state_fio->StateCheckInt32(this_device_id)) {
434                 return false;
435         }
436         for(int i = 0; i < 2; i++) {
437                 if(!disk[i]->process_state(state_fio, loading)) {
438                         return false;
439                 }
440         }
441 //      state_fio->StateBuffer(cur_trk, sizeof(cur_trk), 1);
442 //      state_fio->StateBuffer(cur_sct, sizeof(cur_sct), 1);
443 //      state_fio->StateBuffer(cur_pos, sizeof(cur_pos), 1);
444 //      state_fio->StateBuffer(access, sizeof(access), 1);
445 //      state_fio->StateBuffer(&mdisk, sizeof(DISK60), 1);
446         for(int i = 0; i < (sizeof(cur_trk) / sizeof(int)); i++) {
447                 state_fio->StateInt32(cur_trk[i]);
448         }
449         for(int i = 0; i < (sizeof(cur_sct) / sizeof(int)); i++) {
450                 state_fio->StateInt32(cur_sct[i]);
451         }
452         for(int i = 0; i < (sizeof(cur_pos) / sizeof(int)); i++) {
453                 state_fio->StateInt32(cur_pos[i]);
454         }
455         for(int i = 0; i < (sizeof(access) / sizeof(bool)); i++) {
456                 state_fio->StateBool(access[i]);
457         }
458         // mdisk
459         {
460                 state_fio->StateInt32(mdisk.ATN);
461                 state_fio->StateInt32(mdisk.DAC);
462                 state_fio->StateInt32(mdisk.RFD);
463                 state_fio->StateInt32(mdisk.DAV);
464                 
465                 state_fio->StateInt32(mdisk.command);
466                 state_fio->StateInt32(mdisk.step);
467                 state_fio->StateInt32(mdisk.blk);
468
469                 state_fio->StateInt32(mdisk.drv);
470                 state_fio->StateInt32(mdisk.trk);
471                 state_fio->StateInt32(mdisk.sct);
472                 state_fio->StateInt32(mdisk.size);
473                 
474                 state_fio->StateUint8(mdisk.retdat);
475         }
476         state_fio->StateUint8(io_D1H);
477         state_fio->StateUint8(io_D2H);
478         state_fio->StateUint8(old_D2H);
479         state_fio->StateUint8(io_D3H);
480         state_fio->StateInt32(DrvNum);
481         return true;
482 }
483