OSDN Git Service

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