OSDN Git Service

[VM][General][WIP] Syncing to UPSTREAM 2015-01-21 , work-in-progress.
[csp-qt/common_source_project-fm7.git] / source / src / vm / pc6031.cpp
1 //\r
2 // PC-6001/6601 disk I/O\r
3 // This file is based on a disk I/O program in C++\r
4 // by Mr. Yumitaro and translated into C for Cocoa iP6\r
5 // by Koichi NISHIDA 2006\r
6 //\r
7 \r
8 /*\r
9         Skelton for retropc emulator\r
10 \r
11         Author : Takeda.Toshiya\r
12         Origin : tanam\r
13         Date   : 2014.05.21-\r
14 \r
15         [ PC-6031 ]\r
16 */\r
17 \r
18 #include "pc6031.h"\r
19 #include "disk.h"\r
20 \r
21 int PC6031::Seek88(int drvno, int trackno, int sectno)\r
22 {\r
23         if(drvno < 2) {\r
24                 cur_trk[drvno] = trackno;\r
25                 cur_sct[drvno] = sectno;\r
26                 cur_pos[drvno] = 0;\r
27                 \r
28                 if(disk[drvno]->get_track(trackno >> 1, trackno & 1)) {\r
29                         for(int i = 0; i < disk[drvno]->sector_num; i++) {\r
30                                 if(disk[drvno]->get_sector(trackno >> 1, 0/*trackno & 1*/, i)) {\r
31                                         if(disk[drvno]->id[2] == sectno) {\r
32                                                 return 1;\r
33                                         }\r
34                                 }\r
35                         }\r
36                 }\r
37         }\r
38         return 0;\r
39 }\r
40 \r
41 unsigned char PC6031::Getc88(int drvno)\r
42 {\r
43         if(drvno < 2 && disk[drvno]->sector != NULL) {\r
44                 if(cur_pos[drvno] >= disk[drvno]->sector_size) {\r
45                         cur_sct[drvno]++;\r
46                         if(!Seek88(drvno, cur_trk[drvno], cur_sct[drvno])) {\r
47 //                              cur_trk[drvno]++;\r
48                                 cur_trk[drvno] += 2;\r
49                                 cur_sct[drvno] = 1;\r
50                                 if(!Seek88(drvno, cur_trk[drvno], cur_sct[drvno])) {\r
51                                         return 0xff;\r
52                                 }\r
53                         }\r
54                 }\r
55                 access[drvno] = true;\r
56                 return disk[drvno]->sector[cur_pos[drvno]++];\r
57         }\r
58         return 0xff;\r
59 }\r
60 \r
61 int PC6031::Putc88(int drvno, unsigned char dat)\r
62 {\r
63         if(drvno < 2 && disk[drvno]->sector != NULL) {\r
64                 if(cur_pos[drvno] >= disk[drvno]->sector_size) {\r
65                         cur_sct[drvno]++;\r
66                         if(!Seek88(drvno, cur_trk[drvno], cur_sct[drvno])) {\r
67 //                              cur_trk[drvno]++;\r
68                                 cur_trk[drvno] += 2;\r
69                                 cur_sct[drvno] = 1;\r
70                                 if(!Seek88(drvno, cur_trk[drvno], cur_sct[drvno])) {\r
71                                         return 0xff;\r
72                                 }\r
73                         }\r
74                 }\r
75                 access[drvno] = true;\r
76                 disk[drvno]->sector[cur_pos[drvno]++] = dat;\r
77                 return 1;\r
78         }\r
79         return 0;\r
80 }\r
81 \r
82 // command\r
83 enum FddCommand\r
84 {\r
85         INIT                            = 0x00,\r
86         WRITE_DATA                      = 0x01,\r
87         READ_DATA                       = 0x02,\r
88         SEND_DATA                       = 0x03,\r
89         COPY                            = 0x04,\r
90         FORMAT                          = 0x05,\r
91         SEND_RESULT_STATUS      = 0x06,\r
92         SEND_DRIVE_STATUS       = 0x07,\r
93         TRANSMIT                        = 0x11,\r
94         RECEIVE                         = 0x12,\r
95         LOAD                            = 0x14,\r
96         SAVE                            = 0x15,\r
97         WAIT                            = 0xff, // waiting state\r
98         EndofFdcCmd\r
99 };\r
100 \r
101 // data input (port D0H)\r
102 unsigned char PC6031::FddIn60()\r
103 {\r
104         unsigned char ret;\r
105 \r
106         if (mdisk.DAV) {                // if data is valid\r
107                 if (mdisk.step == 6) {\r
108                         mdisk.retdat = Getc88(mdisk.drv);\r
109                         if(--mdisk.size == 0) mdisk.step = 0;\r
110                 }\r
111                 mdisk.DAC = 1;\r
112                 ret = mdisk.retdat;\r
113         } else {                        // if data is not valid\r
114                 ret = 0xff;\r
115         }\r
116         return ret;\r
117 }\r
118 \r
119 // data/command output (port D1H)\r
120 void PC6031::FddOut60(unsigned char dat)\r
121 {\r
122         if (mdisk.command == WAIT) {    // when command\r
123                 mdisk.command = dat;\r
124                 switch (mdisk.command) {\r
125                 case INIT:                                      // 00h init\r
126                         break;\r
127                 case WRITE_DATA:                        // 01h write data\r
128                         mdisk.step = 1;\r
129                         break;\r
130                 case READ_DATA:                         // 02h read data\r
131                         mdisk.step = 1;\r
132                         break;\r
133                 case SEND_DATA:                         // 03h send data\r
134                         mdisk.step = 6;\r
135                         break;\r
136                 case COPY:                                      // 04h copy\r
137                         break;\r
138                 case FORMAT:                            // 05h format\r
139                         break;\r
140                 case SEND_RESULT_STATUS:        // 06h send result status\r
141                         mdisk.retdat = 0x40;\r
142                         break;\r
143                 case SEND_DRIVE_STATUS:         // 07h send drive status\r
144                         mdisk.retdat |= 0x0a;\r
145                         break;\r
146                 case TRANSMIT:                          // 11h transnmit\r
147                         break;\r
148                 case RECEIVE:                           // 12h receive\r
149                         break;\r
150                 case LOAD:                                      // 14h load\r
151                         break;\r
152                 case SAVE:                                      // 15h save\r
153                         break;\r
154                 }\r
155         } else {                                        // when data\r
156                 switch (mdisk.command) {\r
157                 case WRITE_DATA:                        // 01h write data\r
158                         switch (mdisk.step) {\r
159                         case 1: // 01h:block number\r
160                                 mdisk.blk = dat;\r
161                                 mdisk.size = mdisk.blk*256;\r
162                                 mdisk.step++;\r
163                                 break;\r
164                         case 2: // 02h:drive number - 1\r
165                                 mdisk.drv = dat;\r
166                                 mdisk.step++;\r
167                                 break;\r
168                         case 3: // 03h:track number\r
169                                 mdisk.trk = dat;\r
170                                 mdisk.step++;\r
171                                 break;\r
172                         case 4: // 04h:sector number\r
173                                 mdisk.sct = dat;\r
174                                 // double track number(1D->2D)\r
175                                 Seek88(mdisk.drv, mdisk.trk*2, mdisk.sct);\r
176                                 mdisk.step++;\r
177                                 break;\r
178                         case 5: // 05h:write data\r
179                                 Putc88(mdisk.drv, dat);\r
180                                 if( --mdisk.size == 0 ){\r
181                                         mdisk.step = 0;\r
182                                 }\r
183                                 break;\r
184                         }\r
185                         break;\r
186                 case READ_DATA:                         // 02h read data\r
187                         switch (mdisk.step) {\r
188                         case 1: // 01h:block number\r
189                                 mdisk.blk = dat;\r
190                                 mdisk.size = mdisk.blk*256;\r
191                                 mdisk.step++;\r
192                                 break;\r
193                         case 2: // 02h:drive number-1\r
194                                 mdisk.drv = dat;\r
195                                 mdisk.step++;\r
196                                 break;\r
197                         case 3: // 03h:track number\r
198                                 mdisk.trk = dat;\r
199                                 mdisk.step++;\r
200                                 break;\r
201                         case 4: // 04h:sector number\r
202                                 mdisk.sct = dat;\r
203                                 // double track number(1D->2D)\r
204                                 Seek88(mdisk.drv, mdisk.trk*2, mdisk.sct);\r
205                                 mdisk.step = 0;\r
206                                 break;\r
207                         }\r
208                 }\r
209         }\r
210 }\r
211 \r
212 // control input from disk unit (port D2H)\r
213 unsigned char PC6031::FddCntIn60(void)\r
214 {\r
215         if (((old_D2H & 0x01) ^ mdisk.DAV) || mdisk.RFD && mdisk.DAV) {\r
216                 mdisk.DAC = mdisk.DAV;\r
217         } else if (mdisk.ATN) {\r
218                 mdisk.RFD = 1;\r
219                 mdisk.command = WAIT;\r
220         } else if (mdisk.DAC) {\r
221                 mdisk.DAV = 0;\r
222         } else if (mdisk.RFD) {\r
223                 mdisk.DAV = 1;\r
224         }       \r
225         old_D2H = io_D2H;\r
226         io_D2H = 0xf0 | 0x08 /* (mdisk.ATN<<3) */ | (mdisk.DAC<<2) | (mdisk.RFD<<1) | mdisk.DAV;\r
227         return (io_D2H);\r
228 }\r
229 \r
230 // control output to disk unit (port D3H)\r
231 void PC6031::FddCntOut60(unsigned char dat)\r
232 {\r
233         // 8255 basic behavior\r
234         if (!(dat&0x80)) {              // check msb\r
235                                                         // ignore when 1\r
236                 switch ((dat>>1)&0x07) {\r
237                 case 7: // bit7 ATN\r
238                         mdisk.ATN = dat&1;\r
239                         break;\r
240                 case 6: // bit6 DAC\r
241                         mdisk.DAC = dat&1;\r
242                         break;\r
243                 case 5: // bit5 RFD\r
244                         mdisk.RFD = dat&1;\r
245                         break;\r
246                 case 4: // bit4 DAV\r
247                         mdisk.DAV = dat&1;\r
248                         break;\r
249                 }\r
250                 io_D2H = 0xf0 | 0x08 /* (mdisk.ATN<<3) */ | (mdisk.DAC<<2) | (mdisk.RFD<<1) | mdisk.DAV;\r
251         }\r
252 }\r
253 \r
254 // I/O access functions\r
255 void PC6031::OutD1H_60(unsigned char data) { io_D1H = data; FddOut60(io_D1H); }\r
256 void PC6031::OutD2H_60(unsigned char data) {\r
257         mdisk.ATN = (data & 0x80) >> 7;\r
258         mdisk.DAC = (data & 0x40) >> 6;\r
259         mdisk.RFD = (data & 0x20) >> 5;\r
260         mdisk.DAV = (data & 0x10) >> 4;\r
261         io_D2H = 0xf0 | 0x08 /* (mdisk.ATN<<3) */ | (mdisk.DAC<<2) | (mdisk.RFD<<1) | mdisk.DAV;\r
262 }\r
263 void PC6031::OutD3H_60(unsigned char data) { io_D3H = data; FddCntOut60(io_D3H); }\r
264 \r
265 unsigned char PC6031::InD0H_60() { return FddIn60(); }\r
266 unsigned char PC6031::InD1H_60() { return io_D1H; }\r
267 unsigned char PC6031::InD2H_60() { io_D2H = FddCntIn60(); return io_D2H; }\r
268 unsigned char PC6031::InD3H_60() { return io_D3H; }\r
269 \r
270 void PC6031::initialize()\r
271 {\r
272         for(int i = 0; i < 2; i++) {\r
273                 disk[i] = new DISK();\r
274         }\r
275         DrvNum = 1;\r
276         memset(&mdisk, 0, sizeof(DISK60));\r
277         mdisk.command = WAIT;           // received command\r
278         mdisk.retdat  = 0xff;           // data from port D0H\r
279         io_D1H = 0;\r
280         io_D2H = 0xf0 | 0x08 /* (mdisk.ATN<<3) */ | (mdisk.DAC<<2) | (mdisk.RFD<<1) | mdisk.DAV;\r
281         io_D3H = 0;\r
282         old_D2H = 0;\r
283 }\r
284 \r
285 void PC6031::release()\r
286 {\r
287         for(int i = 0; i < 2; i++) {\r
288                 if(disk[i]) {\r
289                         disk[i]->close();\r
290                         delete disk[i];\r
291                 }\r
292         }\r
293 }\r
294 \r
295 void PC6031::write_io8(uint32 addr, uint32 data)\r
296 {\r
297         switch(addr & 3) {\r
298         case 1:\r
299                 OutD1H_60(data);\r
300                 break;\r
301         case 2:\r
302                 OutD2H_60(data);\r
303                 break;\r
304         case 3:\r
305                 OutD3H_60(data);\r
306                 break;\r
307         }\r
308 }\r
309 \r
310 uint32 PC6031::read_io8(uint32 addr)\r
311 {\r
312         switch(addr & 3) {\r
313         case 0:\r
314                 return InD0H_60(); break;\r
315         case 1:\r
316                 return InD1H_60(); break;\r
317         case 2:\r
318                 return InD2H_60(); break;\r
319         case 3:\r
320                 return InD3H_60(); break;\r
321         }\r
322         return 0xff;\r
323 }\r
324 \r
325 uint32 PC6031::read_signal(int ch)\r
326 {\r
327         // get access status\r
328         uint32 stat = 0;\r
329         for(int drv = 0; drv < 2; drv++) {\r
330                 if(access[drv]) {\r
331                         stat |= 1 << drv;\r
332                 }\r
333                 access[drv] = false;\r
334         }\r
335         return stat;\r
336 }\r
337 \r
338 // ----------------------------------------------------------------------------\r
339 // user interface\r
340 // ----------------------------------------------------------------------------\r
341 \r
342 void PC6031::open_disk(int drv, _TCHAR path[], int offset)\r
343 {\r
344         if(drv < 2) {\r
345                 disk[drv]->open(path, offset);\r
346                 Seek88(drv, 0, 1);\r
347         }\r
348 }\r
349 \r
350 void PC6031::close_disk(int drv)\r
351 {\r
352         if(drv < 2 && disk[drv]->inserted) {\r
353                 disk[drv]->close();\r
354         }\r
355 }\r
356 \r
357 bool PC6031::disk_inserted(int drv)\r
358 {\r
359         if(drv < 2) {\r
360                 return disk[drv]->inserted;\r
361         }\r
362         return false;\r
363 }\r
364 \r
365 bool PC6031::disk_ejected(int drv)\r
366 {\r
367         if(drv < 2) {\r
368                 return disk[drv]->ejected;\r
369         }\r
370         return false;\r
371 }\r
372 \r