OSDN Git Service

d37d304a3ca567788cff98e2eb6b278eaeeba147
[csp-qt/common_source_project-fm7.git] / source / src / vm / mz2500 / mz1e30.cpp
1 /*\r
2         SHARP MZ-2500 Emulator 'EmuZ-2500'\r
3 \r
4         Author : Takeda.Toshiya\r
5         Date   : 2004.09.10 -\r
6 \r
7         [ MZ-1E30 (SASI) ]\r
8 */\r
9 \r
10 #include "mz1e30.h"\r
11 #include "../../fileio.h"\r
12 \r
13 #define PHASE_FREE      0\r
14 #define PHASE_SELECT    1\r
15 #define PHASE_COMMAND   2\r
16 #define PHASE_C2        3\r
17 #define PHASE_SENSE     4\r
18 #define PHASE_READ      5\r
19 #define PHASE_WRITE     6\r
20 #define PHASE_STATUS    7\r
21 #define PHASE_MESSAGE   8\r
22 \r
23 #define STATUS_IXD      0x04\r
24 #define STATUS_CXD      0x08\r
25 #define STATUS_MSG      0x10\r
26 #define STATUS_BSY      0x20\r
27 #define STATUS_REQ      0x80\r
28 \r
29 #define STATUS_IRQ      0\r
30 #define STATUS_DRQ      0\r
31 \r
32 void MZ1E30::initialize()\r
33 {\r
34         // rom file\r
35         FILEIO* fio = new FILEIO();\r
36         if(fio->Fopen(emu->bios_path(_T("MZ-1E30.ROM")), FILEIO_READ_BINARY) ||\r
37            fio->Fopen(emu->bios_path(_T("SASI.ROM")), FILEIO_READ_BINARY) ||\r
38            fio->Fopen(emu->bios_path(_T("FILE.ROM")), FILEIO_READ_BINARY)) {\r
39                 fio->Fseek(0, FILEIO_SEEK_END);\r
40                 if((rom_size = fio->Ftell()) > 0x1000000) {\r
41                         rom_size = 0x1000000;\r
42                 }\r
43                 rom_buffer = (uint8*)malloc(rom_size);\r
44                 \r
45                 fio->Fseek(0, FILEIO_SEEK_SET);\r
46                 fio->Fread(rom_buffer, rom_size, 1);\r
47                 fio->Fclose();\r
48         } else {\r
49                 rom_size = 0;\r
50                 rom_buffer = (uint8*)malloc(1);\r
51         }\r
52         delete fio;\r
53         rom_address = 0;\r
54         \r
55         // open hard drive images\r
56         for(int i = 0; i < 2; i++) {\r
57                 _TCHAR file_name[_MAX_PATH];\r
58                 _stprintf_s(file_name, _MAX_PATH, _T("HDD%d.DAT"), i + 1);\r
59                 \r
60                 drive[i].fio = new FILEIO();\r
61                 if(!drive[i].fio->Fopen(emu->bios_path(file_name), FILEIO_READ_WRITE_BINARY)) {\r
62                         delete drive[i].fio;\r
63                         drive[i].fio = NULL;\r
64                 }\r
65                 drive[i].access = false;\r
66         }\r
67         \r
68         // initialize sasi interface\r
69         memset(buffer, 0, sizeof(buffer));\r
70         memset(cmd, 0, sizeof(cmd));\r
71         memset(status_buf, 0, sizeof(status_buf));\r
72         \r
73         phase = PHASE_FREE;\r
74         sector = 0;\r
75         blocks = 0;\r
76         cmd_ptr = 0;\r
77         unit = 0;\r
78         buffer_ptr = 0;\r
79         status = 0;\r
80         status_irq_drq = 0;\r
81         error = 0;\r
82         status_ptr = 0;\r
83 }\r
84 \r
85 void MZ1E30::release()\r
86 {\r
87         for(int i = 0; i < 2; i++) {\r
88                 if(drive[i].fio != NULL) {\r
89                         drive[i].fio->Fclose();\r
90                         delete drive[i].fio;\r
91                 }\r
92         }\r
93         if(rom_buffer != NULL) {\r
94                 free(rom_buffer);\r
95         }\r
96 }\r
97 \r
98 void MZ1E30::write_io8(uint32 addr, uint32 data)\r
99 {\r
100         switch(addr & 0xff) {\r
101         case 0xa4:\r
102                 // data\r
103                 if(phase == PHASE_COMMAND) {\r
104                         cmd[cmd_ptr++] = data;\r
105                         if(cmd_ptr == 6) {\r
106                                 check_cmd();\r
107                         }\r
108                 } else if(phase == PHASE_C2) {\r
109                         if(++status_ptr == 10) {\r
110                                 set_status(0);\r
111                         }\r
112                 } else if(phase == PHASE_WRITE) {\r
113                         buffer[buffer_ptr++] = data;\r
114                         if(buffer_ptr == 256) {\r
115                                 flush(unit);\r
116                                 if(--blocks) {\r
117                                         sector++;\r
118                                         buffer_ptr = 0;\r
119                                         if(!seek(unit)) {\r
120                                                 set_status(0x0f);\r
121                                                 set_drq(false);\r
122                                         }\r
123                                 } else {\r
124                                         set_status(0);\r
125                                         set_drq(false);\r
126                                 }\r
127                         }\r
128                 }\r
129                 datareg = data;\r
130                 break;\r
131         case 0xa5:\r
132                 // command\r
133                 if(data == 0x00) {\r
134                         if(phase == PHASE_SELECT) {\r
135                                 phase = PHASE_COMMAND;\r
136                                 cmd_ptr = 0;\r
137                         }\r
138                 } else if(data == 0x20) {\r
139                         if(datareg & 1) {\r
140                                 phase = PHASE_SELECT;\r
141                         } else {\r
142                                 phase = PHASE_FREE;\r
143                         }\r
144                 }\r
145                 break;\r
146         case 0xa8:\r
147                 // rom file\r
148                 rom_address = ((addr & 0xff00) << 8) | (data << 8) | (rom_address & 0x0000ff);\r
149                 break;\r
150         }\r
151 }\r
152 \r
153 uint32 MZ1E30::read_io8(uint32 addr)\r
154 {\r
155         uint32 val = 0;\r
156         \r
157         switch(addr & 0xff) {\r
158         case 0xa4:\r
159                 // data\r
160                 if(phase == PHASE_READ) {\r
161                         val = buffer[buffer_ptr++];\r
162                         if(buffer_ptr == 256) {\r
163                                 if(--blocks) {\r
164                                         sector++;\r
165                                         buffer_ptr = 0;\r
166                                         if(!seek(unit)) {\r
167                                                 set_status(0x0f);\r
168                                                 set_drq(false);\r
169                                         }\r
170                                 } else {\r
171                                         set_status(0);\r
172                                         set_drq(false);\r
173                                 }\r
174                         }\r
175                 } else if(phase == PHASE_SENSE) {\r
176                         val = status_buf[status_ptr++];\r
177                         if(status_ptr == 4) {\r
178                                 set_status(0);\r
179                         }\r
180                 } else if(phase == PHASE_STATUS) {\r
181                         val = error ? 0x02 : status;\r
182                         phase = PHASE_MESSAGE;\r
183                 } else if(phase == PHASE_MESSAGE) {\r
184                         phase = PHASE_FREE;\r
185                 }\r
186                 return val;\r
187         case 0xa5:\r
188                 // status\r
189                 val = status_irq_drq;\r
190                 status_irq_drq &= ~STATUS_IRQ;\r
191                 if(phase != PHASE_FREE) {\r
192                         val |= STATUS_BSY;\r
193                 }\r
194                 if(phase > PHASE_SELECT) {\r
195                         val |= STATUS_REQ;\r
196                 }\r
197                 if(phase == PHASE_COMMAND) {\r
198                         val |= STATUS_CXD;\r
199                 }\r
200                 if(phase == PHASE_SENSE) {\r
201                         val |= STATUS_IXD;\r
202                 }\r
203                 if(phase == PHASE_READ) {\r
204                         val |= STATUS_IXD;\r
205                 }\r
206                 if(phase == PHASE_STATUS) {\r
207                         val |= STATUS_IXD | STATUS_CXD;\r
208                 }\r
209                 if(phase == PHASE_MESSAGE) {\r
210                         val |= STATUS_IXD | STATUS_CXD | STATUS_MSG;\r
211                 }\r
212                 return val;\r
213         case 0xa9:\r
214                 // rom file\r
215                 rom_address = (rom_address & 0xffff00) | ((addr & 0xff00) >> 8);\r
216                 if(rom_address < rom_size) {\r
217                         return rom_buffer[rom_address];\r
218                 }\r
219                 break;\r
220         }\r
221         return 0xff;\r
222 }\r
223 \r
224 void MZ1E30::write_dma_io8(uint32 addr, uint32 data)\r
225 {\r
226         write_io8(0xa4, data);\r
227 }\r
228 \r
229 uint32 MZ1E30::read_dma_io8(uint32 addr)\r
230 {\r
231         return read_io8(0xa4);\r
232 }\r
233 \r
234 uint32 MZ1E30::read_signal(int ch)\r
235 {\r
236         // get access status\r
237         uint32 stat = (drive[0].access ? 0x10 : 0) | (drive[1].access ? 0x20 : 0);\r
238         drive[0].access = drive[1].access = false;\r
239         return stat;\r
240 }\r
241 \r
242 void MZ1E30::check_cmd()\r
243 {\r
244         unit = (cmd[1] >> 5) & 1;\r
245         \r
246         switch(cmd[0]) {\r
247         case 0x00:\r
248                 // test drive ready\r
249                 if(drive[unit].fio != NULL) {\r
250                         status = 0x00;\r
251                         set_status(0x00);\r
252                 } else {\r
253                         status = 0x02;\r
254                         set_status(0x7f);\r
255                 }\r
256                 break;\r
257         case 0x01:\r
258                 // recalib\r
259                 if(drive[unit].fio != NULL) {\r
260                         sector = 0;\r
261                         status = 0x00;\r
262                         set_status(0x00);\r
263                 } else {\r
264                         status = 0x02;\r
265                         set_status(0x7f);\r
266                 }\r
267                 break;\r
268         case 0x03:\r
269                 // request sense status\r
270                 phase = PHASE_SENSE;\r
271                 status_buf[0] = error;\r
272                 status_buf[1] = (uint8)((unit << 5) | ((sector >> 16) & 0x1f));\r
273                 status_buf[2] = (uint8)(sector >> 8);\r
274                 status_buf[3] = (uint8)sector;\r
275                 error = 0;\r
276                 status = 0x00;\r
277                 status_ptr = 0;\r
278                 break;\r
279         case 0x04:\r
280                 // format drive\r
281                 sector = 0;\r
282                 status = 0x00;\r
283                 set_status(0x0f);\r
284                 break;\r
285         case 0x06:\r
286                 // format track\r
287                 sector = cmd[1] & 0x1f;\r
288                 sector = (sector << 8) | cmd[2];\r
289                 sector = (sector << 8) | cmd[3];\r
290                 blocks = cmd[4];\r
291                 status = 0;\r
292                 if(format(unit)) {\r
293                         set_status(0);\r
294                 } else {\r
295                         set_status(0x0f);\r
296                 }\r
297                 break;\r
298         case 0x08:\r
299                 // read data\r
300                 sector = cmd[1] & 0x1f;\r
301                 sector = (sector << 8) | cmd[2];\r
302                 sector = (sector << 8) | cmd[3];\r
303                 blocks = cmd[4];\r
304                 status = 0;\r
305                 if(blocks != 0 && seek(unit)) {\r
306                         phase = PHASE_READ;\r
307                         buffer_ptr = 0;\r
308                         set_drq(true);\r
309                 } else {\r
310                         set_status(0x0f);\r
311                 }\r
312                 break;\r
313         case 0x0a:\r
314                 sector = cmd[1] & 0x1f;\r
315                 sector = (sector << 8) | cmd[2];\r
316                 sector = (sector << 8) | cmd[3];\r
317                 blocks = cmd[4];\r
318                 status = 0;\r
319                 if(blocks != 0 && seek(unit)) {\r
320                         phase = PHASE_WRITE;\r
321                         buffer_ptr = 0;\r
322                         memset(buffer, 0, sizeof(buffer));\r
323                         set_drq(true);\r
324                 } else {\r
325                         set_status(0x0f);\r
326                 }\r
327                 break;\r
328         case 0x0b:\r
329                 sector = cmd[1] & 0x1f;\r
330                 sector = (sector << 8) | cmd[2];\r
331                 sector = (sector << 8) | cmd[3];\r
332                 blocks = cmd[4];\r
333                 status = 0;\r
334                 set_status(0);\r
335                 break;\r
336         case 0xc2:\r
337                 phase = PHASE_C2;\r
338                 status_ptr = 0;\r
339                 status = 0;\r
340 //              error = 0;\r
341                 break;\r
342         default:\r
343                 // unknown\r
344                 set_status(0);\r
345                 break;\r
346         }\r
347 }\r
348 \r
349 void MZ1E30::set_status(uint8 err)\r
350 {\r
351         error = err;\r
352 #if 1\r
353         phase = PHASE_STATUS;\r
354         // raise irq\r
355         status_irq_drq |= STATUS_IRQ;\r
356 #else\r
357         vm->register_event(this, 0, 10, false, NULL);\r
358 #endif\r
359 }\r
360 \r
361 void MZ1E30::event_callback(int event_id, int err)\r
362 {\r
363 #if 0\r
364         phase = PHASE_STATUS;\r
365         // raise irq\r
366         status_irq_drq |= STATUS_IRQ;\r
367 #endif\r
368 }\r
369 \r
370 void MZ1E30::set_drq(bool flag)\r
371 {\r
372         if(flag) {\r
373                 status_irq_drq |= STATUS_DRQ;\r
374         } else {\r
375                 status_irq_drq &= ~STATUS_DRQ;\r
376         }\r
377 }\r
378 \r
379 bool MZ1E30::seek(int drv)\r
380 {\r
381         memset(buffer, 0, sizeof(buffer));\r
382         \r
383         if(drive[drv & 1].fio == NULL) {\r
384                 return false;\r
385         }\r
386         if(drive[drv & 1].fio->Fseek(sector * 256, FILEIO_SEEK_SET) != 0) {\r
387                 return false;\r
388         }\r
389         if(drive[drv & 1].fio->Fread(buffer, 256, 1) != 1) {\r
390                 return false;\r
391         }\r
392         drive[drv & 1].access = true;\r
393         return true;\r
394 }\r
395 \r
396 bool MZ1E30::flush(int drv)\r
397 {\r
398         if(drive[drv & 1].fio == NULL) {\r
399                 return false;\r
400         }\r
401         if(drive[drv & 1].fio->Fseek(sector * 256, FILEIO_SEEK_SET) != 0) {\r
402                 return false;\r
403         }\r
404         if(drive[drv & 1].fio->Fwrite(buffer, 256, 1) != 1) {\r
405                 return false;\r
406         }\r
407         drive[drv & 1].access = true;\r
408         return true;\r
409 }\r
410 \r
411 bool MZ1E30::format(int drv)\r
412 {\r
413         if(drive[drv & 1].fio == NULL) {\r
414                 return false;\r
415         }\r
416         if(drive[drv & 1].fio->Fseek(sector * 256, FILEIO_SEEK_SET) != 0) {\r
417                 return false;\r
418         }\r
419         // format 33 blocks\r
420         memset(buffer, 0, sizeof(buffer));\r
421         for(int i = 0; i < 33; i++) {\r
422                 if(drive[drv & 1].fio->Fwrite(buffer, 256, 1) != 1) {\r
423                         return false;\r
424                 }\r
425                 drive[drv & 1].access = true;\r
426         }\r
427         return true;\r
428 }\r
429 \r
430 #define STATE_VERSION   1\r
431 \r
432 void MZ1E30::save_state(FILEIO* state_fio)\r
433 {\r
434         state_fio->FputUint32(STATE_VERSION);\r
435         state_fio->FputInt32(this_device_id);\r
436         \r
437         state_fio->FputUint32(rom_address);\r
438         state_fio->Fwrite(buffer, sizeof(buffer), 1);\r
439         state_fio->FputInt32(phase);\r
440         state_fio->FputInt32(sector);\r
441         state_fio->FputInt32(blocks);\r
442         state_fio->Fwrite(cmd, sizeof(cmd), 1);\r
443         state_fio->FputInt32(cmd_ptr);\r
444         state_fio->FputInt32(unit);\r
445         state_fio->FputInt32(buffer_ptr);\r
446         state_fio->FputUint8(status);\r
447         state_fio->FputUint8(status_irq_drq);\r
448         state_fio->FputUint8(error);\r
449         state_fio->Fwrite(status_buf, sizeof(status_buf), 1);\r
450         state_fio->FputInt32(status_ptr);\r
451         state_fio->FputUint8(datareg);\r
452 }\r
453 \r
454 bool MZ1E30::load_state(FILEIO* state_fio)\r
455 {\r
456         if(state_fio->FgetUint32() != STATE_VERSION) {\r
457                 return false;\r
458         }\r
459         if(state_fio->FgetInt32() != this_device_id) {\r
460                 return false;\r
461         }\r
462         rom_address = state_fio->FgetUint32();\r
463         state_fio->Fread(buffer, sizeof(buffer), 1);\r
464         phase = state_fio->FgetInt32();\r
465         sector = state_fio->FgetInt32();\r
466         blocks = state_fio->FgetInt32();\r
467         state_fio->Fread(cmd, sizeof(cmd), 1);\r
468         cmd_ptr = state_fio->FgetInt32();\r
469         unit = state_fio->FgetInt32();\r
470         buffer_ptr = state_fio->FgetInt32();\r
471         status = state_fio->FgetUint8();\r
472         status_irq_drq = state_fio->FgetUint8();\r
473         error = state_fio->FgetUint8();\r
474         state_fio->Fread(status_buf, sizeof(status_buf), 1);\r
475         status_ptr = state_fio->FgetInt32();\r
476         datareg = state_fio->FgetUint8();\r
477         return true;\r
478 }\r
479 \r