OSDN Git Service

[VM][FM7][FLOPPY] Fix crash when starting.
[csp-qt/common_source_project-fm7.git] / source / src / vm / fm7 / floppy.cpp
1 /*
2  * FM-7 Main I/O -> FDC [floppy.cpp]
3  *
4  * Author: K.Ohta <whatisthis.sowhat _at_ gmail.com>
5  * License: GPLv2
6  * History:
7  *   Mar 19, 2015 : Initial, split from fm7_mainio.cpp .
8  *
9  */
10
11 #include "fm7_mainio.h"
12
13 #include "../mc6809.h"
14 #include "../z80.h"
15
16 #include "../mb8877.h"
17 #include "../disk.h"
18 #if defined(HAS_DMA)
19 #include "hd6844.h"
20 #endif
21
22 #define FDC_CMD_TYPE1           1
23 #define FDC_CMD_RD_SEC          2
24 #define FDC_CMD_RD_MSEC         3
25 #define FDC_CMD_WR_SEC          4
26 #define FDC_CMD_WR_MSEC         5
27 #define FDC_CMD_RD_ADDR         6
28 #define FDC_CMD_RD_TRK          7
29 #define FDC_CMD_WR_TRK          8
30 #define FDC_CMD_TYPE4           0x80
31
32 void FM7_MAINIO::reset_fdc(void)
33 {
34         if(connect_fdc) {
35                 fdc_cmdreg = 0;
36                 fdc_statreg = fdc->read_io8(0);
37                 fdc_trackreg = fdc->read_io8(1);
38                 fdc_sectreg = fdc->read_io8(2);
39                 fdc_datareg = fdc->read_io8(3);
40                 fdc_headreg = 0xfe | fdc->read_signal(SIG_MB8877_SIDEREG);
41                 fdc_drvsel = 0x7c | fdc->read_signal(SIG_MB8877_DRIVEREG);
42                 irqreg_fdc = 0x00; //0b00000000;
43         }
44         //fdc_motor = (fdc->read_signal(SIG_MB8877_MOTOR) != 0);
45         fdc_motor = false;
46         fdc_cmd_type1 = false;
47         
48 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || \
49         defined(_FM77AV20) || defined(_FM77AV20EX)
50         if(connect_fdc) {
51                 fdc_reg_fd1e = 0x80;
52                 for(int i = 0; i < 4; i++) {
53                         fdc_drive_table[i] = (uint8_t)i;
54                         fdc->set_drive_type(i, DRIVE_TYPE_2D);
55                 }
56         }
57 #else
58         if(connect_fdc) {
59                 for(int i = 0; i < 4; i++) {
60                         fdc->set_drive_type(i, DRIVE_TYPE_2D);
61                 }
62         }
63 #endif  
64         if(event_fdc_motor >= 0) cancel_event(this, event_fdc_motor);
65         event_fdc_motor = -1;
66         irqstat_fdc = false;
67         irqmask_mfd = true;
68         if(connect_fdc) {
69                 set_fdc_motor(fdc_motor);
70         }
71 }
72
73 /* FDD */
74
75 void FM7_MAINIO::set_fdc_cmd(uint8_t val)
76 {
77         if(!connect_fdc) return;
78         //irqreg_fdc = 0x00;
79         fdc_cmdreg = val;
80         fdc_cmd_type1 = ((val & 0x80) == 0);
81 #if defined(HAS_DMA)
82         if(((fdc_cmdreg >= 0x80) && (fdc_cmdreg < 0xd0)) || (fdc_cmdreg >= 0xe0)) {
83                 uint32_t words = dmac->read_signal(HD6844_WORDS_REG_0);
84                 if((words != 0) && (words < 0xffff) && (dmac->read_signal(HD6844_IS_TRANSFER_0) == 0)) {
85                         dmac->write_signal(HD6844_SRC_FIXED_ADDR_CH0, 3, 0xffffffff);
86                         dmac->write_signal(HD6844_TRANSFER_START, 0, 0xffffffff);
87                         //this->out_debug_log(_T("FDC: Start DMA CMDREG=%02x CHRN=%02x %02x %02x * DRVSEL=%08x\n"),
88                         //                                       fdc_cmdreg, fdc_trackreg, fdc_headreg & 0x01, fdc_sectreg, fdc_drvsel);
89                 }
90         }
91 #endif  
92         fdc->write_io8(0, val & 0x00ff);
93 #ifdef _FM7_FDC_DEBUG   
94         this->out_debug_log(_T("FDC: CMD: $%02x"), fdc_cmdreg);
95 #endif  
96 }
97
98 uint8_t FM7_MAINIO::get_fdc_stat(void)
99 {
100         uint32_t stat_backup = fdc_statreg;
101         if(!connect_fdc) return 0xff;
102         fdc_statreg =  fdc->read_io8(0);
103 #ifdef _FM7_FDC_DEBUG   
104         if(stat_backup != fdc_statreg) this->out_debug_log(_T("FDC: \nGet Stat(not busy): $%02x"), fdc_statreg);
105 #endif  
106         return fdc_statreg;
107 }
108
109 void FM7_MAINIO::set_fdc_track(uint8_t val)
110 {
111         if(!connect_fdc) return;
112         // if mode is 2DD and type-of-image = 2D then val >>= 1;
113         
114         fdc_trackreg = val;
115 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || \
116         defined(_FM77AV20) || defined(_FM77AV20EX)
117         uint32_t d;
118         if((fdc_drvsel & 0x40) == 0) {
119                 d = fdc_drive_table[fdc_drvsel & 0x03] & 0x03;
120         } else {
121                 d = fdc_drvsel & 0x03;
122         }
123         DISK *disk = fdc->get_disk_handler(d);
124         if(disk->media_type != MEDIA_TYPE_2D){
125                 if(disk->drive_type == DRIVE_TYPE_2D) val <<= 1;
126         } else { 
127                 //if(disk->drive_type != DRIVE_TYPE_2D) val >>= 1;
128         }
129 #endif  
130         fdc->write_io8(1, val);
131 #ifdef _FM7_FDC_DEBUG   
132         this->out_debug_log(_T("FDC : Set Track: %d"), val);
133 #endif  
134 }
135
136 uint8_t FM7_MAINIO::get_fdc_track(void)
137 {
138         if(!connect_fdc) return 0xff;
139         fdc_trackreg = fdc->read_io8(1);
140         return fdc_trackreg;
141 }
142
143 void FM7_MAINIO::set_fdc_sector(uint8_t val)
144 {
145         if(!connect_fdc) return;
146         fdc_sectreg = val;
147         fdc->write_io8(2, val);
148 #ifdef _FM7_FDC_DEBUG   
149         this->out_debug_log(_T("FDC: Set Sector: $%02x"), val);
150 #endif  
151 }
152
153 uint8_t FM7_MAINIO::get_fdc_sector(void)
154 {
155         if(!connect_fdc) return 0xff;
156         fdc_sectreg = fdc->read_io8(2);
157         return fdc_sectreg;
158 }
159   
160 void FM7_MAINIO::set_fdc_data(uint8_t val)
161 {
162         if(!connect_fdc) return;
163         fdc_datareg = val;
164         fdc->write_io8(3, val & 0x00ff);
165 }
166
167 uint8_t FM7_MAINIO::get_fdc_data(void)
168 {
169         if(!connect_fdc) return 0xff;
170         fdc_datareg = fdc->read_io8(3);
171         
172         return fdc_datareg;
173 }
174
175 uint8_t FM7_MAINIO::get_fdc_motor(void)
176 {
177         uint8_t val = 0x3c; //0b01111100;
178         if(!connect_fdc) return 0xff;
179         fdc_motor = (fdc->read_signal(SIG_MB8877_MOTOR) != 0) ? true : false;
180         if(fdc_motor) val |= 0x80;
181         //fdc_drvsel = fdc->read_signal(SIG_MB8877_READ_DRIVE_REG);
182         val = val | (fdc_drvsel & 0x03);
183 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || \
184         defined(_FM77AV20) || defined(_FM77AV20EX)
185         val = val | (fdc_drvsel & 0x40);
186 #endif  
187 #ifdef _FM7_FDC_DEBUG   
188         this->out_debug_log(_T("FDC: Get motor/Drive: $%02x"), val);
189 #endif  
190         return val;
191 }
192   
193 void FM7_MAINIO::set_fdc_fd1c(uint8_t val)
194 {
195         if(!connect_fdc) return;
196         fdc_headreg = (val & 0x01) | 0xfe;
197         fdc->write_signal(SIG_MB8877_SIDEREG, val, 0x01);
198 #ifdef _FM7_FDC_DEBUG   
199         this->out_debug_log(_T("FDC: Set side/head: $%02x"), val);
200 #endif  
201 }
202
203 uint8_t FM7_MAINIO::get_fdc_fd1c(void)
204 {
205         if(!connect_fdc) return 0xff;
206         //fdc_headreg = fdc->read_signal(SIG_MB8877_SIDEREG);
207         return fdc_headreg;
208 }
209
210 void FM7_MAINIO::set_fdc_fd1d(uint8_t val)
211 {
212         bool backup_motor = fdc_motor;
213         bool f;
214         if(!connect_fdc) return;
215         if((val & 0x80) != 0) {
216                 f = true;
217         } else {
218                 f = false;
219         }
220
221 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || \
222         defined(_FM77AV20) || defined(_FM77AV20EX)
223         if((val & 0x40) == 0) {
224                 fdc->write_signal(SIG_MB8877_DRIVEREG, fdc_drive_table[val & 0x03], 0x03);
225         } else {
226                 fdc->write_signal(SIG_MB8877_DRIVEREG, val, 0x03);
227         }
228         fdc_drvsel = val;
229 #else
230         fdc->write_signal(SIG_MB8877_DRIVEREG, val, 0x03);
231         fdc_drvsel = val;
232 #endif  
233
234         if(f != backup_motor) {
235                 if(event_fdc_motor >= 0) cancel_event(this, event_fdc_motor);
236                 if(f) {
237                         register_event(this, EVENT_FD_MOTOR_ON, 1000.0 * 300.0, false, &event_fdc_motor); // Motor ON After 0.3Sec.
238                 } else {
239                         register_event(this, EVENT_FD_MOTOR_OFF, 1000.0 * 50.0, false, &event_fdc_motor); // Motor OFF After 0.05Sec.
240                 }
241         }
242 #ifdef _FM7_FDC_DEBUG   
243         this->out_debug_log(_T("FDC: Set Drive Select: $%02x"), val);
244 #endif  
245 }
246
247 uint8_t FM7_MAINIO::get_fdc_fd1e(void)
248 {
249 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || \
250         defined(_FM77AV20) || defined(_FM77AV20EX)
251         uint8_t val = 0xa0;
252         val |= (fdc_reg_fd1e & 0x5f);
253         return val;
254 #else
255         return 0xff;
256 #endif
257 }       
258
259 void FM7_MAINIO::set_fdc_fd1e(uint8_t val)
260 {
261 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || \
262         defined(_FM77AV20) || defined(_FM77AV20EX)
263         uint8_t drive;
264         if(!connect_fdc) return;
265         
266         fdc_reg_fd1e = val;
267         
268         if((val & 0x10) != 0) {
269                 fdc_drive_table[(val & 0x0c) >> 2] = val & 0x03;
270                 if(((val & 0x0c) >> 2) == (fdc_drvsel & 0x03)) {
271                         fdc->write_signal(SIG_MB8877_DRIVEREG, fdc_drive_table[(val & 0x0c) >> 2], 0x03);
272                 }
273         }
274         if((val & 0x40) != 0) {
275                 for(drive = 0; drive < MAX_DRIVE; drive++) fdc->set_drive_type(drive, DRIVE_TYPE_2D);
276                 //this->out_debug_log(_T("2D\n"));
277         } else {
278                 for(drive = 0; drive < MAX_DRIVE; drive++) fdc->set_drive_type(drive, DRIVE_TYPE_2DD);
279                 //this->out_debug_log(_T("2DD\n"));
280         }
281 #endif  
282 }
283 void FM7_MAINIO::set_irq_mfd(bool flag)
284 {
285         bool backup = irqstat_fdc;
286         if(!connect_fdc) return;
287         if(flag) {
288                 irqreg_fdc |= 0x40; //0b01000000;
289         } else {
290                 irqreg_fdc &= 0xbf; //0b10111111;
291         }
292 #if !defined(_FM8) // With FM8, $FD1F is alive and not do_irq(), Thanks to Anna_Wu.
293         irqstat_fdc = flag & !irqmask_mfd;
294         if(backup != irqstat_fdc) do_irq();
295 #endif
296         return;
297 }
298
299 void FM7_MAINIO::set_drq_mfd(bool flag)
300 {
301         if(!connect_fdc) return;
302         if(flag) {
303                 irqreg_fdc |= 0x80;//0b10000000;
304         } else {
305                 irqreg_fdc &= 0x7f; //0b01111111;
306         }
307 #if defined(HAS_DMA)
308         if((dmac->read_signal(HD6844_IS_TRANSFER_0) != 0) && (flag)) {
309                 dmac->write_signal(HD6844_DO_TRANSFER, 0x0, 0xffffffff);
310         }
311 #endif  
312         return;
313 }
314
315 uint8_t FM7_MAINIO::fdc_getdrqirq(void)
316 {
317         uint8_t val = irqreg_fdc | 0x3f;
318         if(!connect_fdc) return 0xff;
319         return val;
320 }
321
322 void FM7_MAINIO::set_fdc_motor(bool flag)
323 {
324         if(!connect_fdc) return;
325         fdc->write_signal(SIG_MB8877_MOTOR, flag ? 0x01 : 0x00, 0x01);
326         fdc_motor = (fdc->read_signal(SIG_MB8877_MOTOR) != 0);
327 }