OSDN Git Service

f56c9f7211111e583a0ae5c400227e3c882ac6c8
[csp-qt/common_source_project-fm7.git] / source / src / vm / fmr50 / bios.cpp
1 /*
2         FUJITSU FMR-30 Emulator 'eFMR-30'
3         FUJITSU FMR-50 Emulator 'eFMR-50'
4         FUJITSU FMR-60 Emulator 'eFMR-60'
5
6         Author : Takeda.Toshiya
7         Date   : 2008.10.06 -
8
9         [ bios ]
10 */
11
12 #include "bios.h"
13 #include "../disk.h"
14
15 // regs
16 #define AX      regs[0]
17 #define CX      regs[1]
18 #define DX      regs[2]
19 #define BX      regs[3]
20 #define SP      regs[4]
21 #define BP      regs[5]
22 #define SI      regs[6]
23 #define DI      regs[7]
24
25 #define AL      regs8[0]
26 #define AH      regs8[1]
27 #define CL      regs8[2]
28 #define CH      regs8[3]
29 #define DL      regs8[4]
30 #define DH      regs8[5]
31 #define BL      regs8[6]
32 #define BH      regs8[7]
33 #define SPL     regs8[8]
34 #define SPH     regs8[9]
35 #define BPL     regs8[10]
36 #define BPH     regs8[11]
37 #define SIL     regs8[12]
38 #define SIH     regs8[13]
39 #define DIL     regs8[14]
40 #define DIH     regs8[15]
41
42 // sregs
43 #define ES      sregs[0]
44 #define CS      sregs[1]
45 #define SS      sregs[2]
46 #define DS      sregs[3]
47
48 // error
49 #define ERR_FDD_NOTREADY        1
50 #define ERR_FDD_PROTECTED       2
51 #define ERR_FDD_DELETED         4
52 #define ERR_FDD_NOTFOUND        8
53 #define ERR_FDD_CRCERROR        0x10
54 #define ERR_SCSI_NOTREADY       1
55 #define ERR_SCSI_PARAMERROR     2
56 #define ERR_SCSI_NOTCONNECTED   4
57
58 #if defined(_FMR30)
59 // FMR-30
60 #define CMOS_SIZE       0x2000
61 #define VRAM_SIZE       0x20000
62 #define IPL_SIZE        0x10000
63 #define IPL_ID          '2'
64 #elif defined(_FMR50)
65 // FMR-50
66 #define CMOS_SIZE       0x800
67 #define VRAM_SIZE       0x40000
68 #define IPL_SIZE        0x4000
69 #define IPL_ID          '1'
70 #elif defined(_FMR60)
71 // FMR-60
72 #define CMOS_SIZE       0x800
73 #define VRAM_SIZE       0x80000
74 #define IPL_SIZE        0x4000
75 #define IPL_ID          '1'
76 #endif
77
78 #define BLOCK_SIZE      512
79
80 static const int iotable[][2] = {
81 #ifdef _FMR30
82         {0x0100, 0x19}, // pic
83         {0x0101, 0x40},
84         {0x0101, 0x80},
85         {0x0101, 0x01},
86         {0x0101, 0xff},
87         {0x0108, 0x19},
88         {0x010a, 0x48},
89         {0x010a, 0x07},
90         {0x010a, 0x01},
91         {0x010a, 0xff},
92         {0x0042, 0x00}, // timer
93         {0x0133, 0x30},
94         {0x0130, 0xa0},
95         {0x0130, 0x86},
96         {0x000b, 0x02}, // sio
97         {0x0009, 0x00},
98         {0x0009, 0x50},
99         {0x0009, 0x7f},
100         {0x0009, 0x15},
101         {0x0013, 0x02},
102         {0x001d, 0x02}, // memory
103         {0x001e, 0x00},
104         {0x0040, 0x9f}, // psg
105         {0x0040, 0xbf},
106         {0x0040, 0xdf},
107         {0x0040, 0xff},
108         {0x0300, 0x01}, // lcdc
109         {0x0302, 0x50},
110         {0x0300, 0x09},
111         {0x0302, 0x0f},
112         {0x0300, 0x0a},
113         {0x0302, 0x20},
114         {0x0300, 0x0b},
115         {0x0302, 0x0d},
116         {0x0300, 0x0c},
117         {0x0302, 0x00},
118         {0x0300, 0x0d},
119         {0x0302, 0x00},
120         {0x0300, 0x0e},
121         {0x0302, 0x00},
122         {0x0300, 0x0f},
123         {0x0302, 0x00},
124         {0x0300, 0x11},
125         {0x0302, 0xc7},
126         {0x0300, 0x1d},
127         {0x0302, 0x00},
128         {0x0308, 0x63},
129         {0x0309, 0x00},
130         {0x030a, 0x00},
131 #else
132         {0x0060, 0x00}, // timer
133         {0x0604, 0x00}, // keyboard
134         {0x0000, 0x19}, // pic
135         {0x0002, 0x40},
136         {0x0002, 0x80},
137         {0x0002, 0x0d},
138         {0x0002, 0xfe},
139         {0x0010, 0x19},
140         {0x0012, 0x48},
141         {0x0012, 0x87},
142         {0x0012, 0x09},
143         {0x0012, 0xff},
144         {0x0000, 0x20},
145         {0x0046, 0x36}, // pit
146         {0x0040, 0x00},
147         {0x0040, 0x78},
148         {0x0404, 0x00}, // memory
149         {0x0500, 0x00}, // crtc
150         {0x0502, 0x35},
151         {0x0500, 0x01},
152         {0x0502, 0x28},
153         {0x0500, 0x02},
154         {0x0502, 0x2c},
155         {0x0500, 0x03},
156         {0x0502, 0x04},
157         {0x0500, 0x04},
158         {0x0502, 0x1a},
159         {0x0500, 0x05},
160         {0x0502, 0x08},
161         {0x0500, 0x06},
162         {0x0502, 0x19},
163         {0x0500, 0x07},
164         {0x0502, 0x19},
165         {0x0500, 0x08},
166         {0x0502, 0x00},
167         {0x0500, 0x09},
168         {0x0502, 0x0f},
169         {0x0500, 0x0a},
170         {0x0502, 0x20},
171         {0x0500, 0x0b},
172         {0x0502, 0x1e},
173         {0x0500, 0x0c},
174         {0x0502, 0x00},
175         {0x0500, 0x0d},
176         {0x0502, 0x00},
177         {0x0500, 0x0e},
178         {0x0502, 0x00},
179         {0x0500, 0x0f},
180         {0x0502, 0x00},
181         {0x0500, 0x10},
182         {0x0502, 0x00},
183         {0x0500, 0x11},
184         {0x0502, 0x00},
185         {0x0500, 0x1e},
186         {0x0502, 0x00},
187         {0x0500, 0x1f},
188         {0x0502, 0x00},
189         {0xfd98, 0x00}, // palette
190         {0xfd99, 0x01},
191         {0xfd9a, 0x02},
192         {0xfd9b, 0x03},
193         {0xfd9c, 0x04},
194         {0xfd9d, 0x05},
195         {0xfd9e, 0x06},
196         {0xfd9f, 0x07},
197         {0xfda0, 0x0f}, // video
198 #endif
199         {-1, -1}
200 };
201
202 // cmos: $000-
203 static const uint8_t cmos_t[] = {
204 #ifdef _FMR30
205         0x01,0xff,0x42,0x4f,0x4f,0x54,0xa8,0x00,0x40,0x00,0x01,0xfe,0x53,0x45,0x54,0x55,
206         0xe8,0x00,0x00,0x01,0x01,0xfd,0x4c,0x4f,0x47,0x20,0xe8,0x01,0x10,0x03,0x01,0xfc,
207         0x4f,0x41,0x53,0x59,0xf8,0x04,0x20,0x00,0x01,0xfb,0x44,0x45,0x42,0x20,0x18,0x05,
208         0x00,0x01,0x01,0xfa,0x44,0x45,0x53,0x4b,0x18,0x06,0x32,0x00,0x00,0x00,0x00,0x00,
209         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
210         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
211         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
212         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
213         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
214         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
215         0x4a,0x06,0x7b,0x19,0x97,0x62,0x79,0x41
216 #else
217         0x01,0xff,0x42,0x4f,0x4f,0x54,0xa8,0x00,0x40,0x00,0x01,0xfe,0x53,0x45,0x54,0x55,
218         0xe8,0x00,0x00,0x01,0x01,0xfd,0x4c,0x4f,0x47,0x20,0xe8,0x01,0x10,0x03,0x01,0xfc,
219         0x4f,0x41,0x53,0x59,0xf8,0x04,0x20,0x00,0x01,0xfb,0x58,0x45,0x4e,0x49,0x18,0x05,
220         0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
221         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
222         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
223         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
224         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
225         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
226         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
227 //      0x28,0x05,0x99,0x02,0xe1,0xe1,0x79,0x41
228         0x28,0x05,0x99,0x02,0x00,0x00,0x79,0x41
229 #endif
230 };
231 // FMR-30: cmos $1fd0-
232 // FMR-50: cmos $7d0-
233 static const uint8_t cmos_b[] = {
234 #ifdef _FMR30
235         0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0xff,0xff,0xff,0xff,0xff,
236         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
237         0x7f,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
238 #else
239         0x00,0x00,0x01,0x02,0x03,0x04,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
240         0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
241         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
242 #endif
243 };
244
245 // boot message
246 static const uint8_t msg_c[] = {
247         0xff,0x47,0xff,0x07,0xff,0x47,0xff,0x07,0xff,0x47,0xff,0x07,0xff,0x47,0xff,0x07,
248         0xff,0x47,0xff,0x07,0xff,0x47,0xff,0x07,0xff,0x47,0xff,0x07,0xff,0x47,0xff,0x07,
249         0xff,0x47,0xff,0x07,0xff,0x47,0xff,0x07,0xff,0x47,0xff,0x07,0xff,0x47,0xff,0x07,
250         0xff,0x47,0xff,0x07,0xff,0x47,0xff,0x07,0xff,0x47,0xff,0x07
251 };
252
253 // '\83V\83X\83e\83\80\82ð\83Z\83b\83g\82µ\82Ä\82­\82¾\82³\82¢'
254 static const uint8_t msg_k[] = {
255         0x25,0x37,0x00,0x00,0x25,0x39,0x00,0x00,0x25,0x46,0x00,0x00,0x25,0x60,0x00,0x00,
256         0x24,0x72,0x00,0x00,0x25,0x3b,0x00,0x00,0x25,0x43,0x00,0x00,0x25,0x48,0x00,0x00,
257         0x24,0x37,0x00,0x00,0x24,0x46,0x00,0x00,0x24,0x2f,0x00,0x00,0x24,0x40,0x00,0x00,
258         0x24,0x35,0x00,0x00,0x24,0x24,0x00,0x00,0x21,0x21,0x00,0x00
259 };
260
261 void BIOS::initialize()
262 {
263         // to increment timeout counter
264         register_frame_event(this);
265         
266         // check scsi drives
267         FILEIO* fio = new FILEIO();
268         for(int i = 0; i < MAX_SCSI; i++) {
269                 if(fio->Fopen(create_local_path(_T("SCSI%d.DAT"), i), FILEIO_READ_WRITE_BINARY)) {
270                         uint32_t file_size = fio->FileLength();
271                         if(file_size == 0) {
272                                 // from ../scsi_hdd.cpp
273                                 #define SCSI_BUFFER_SIZE        0x10000
274                                 uint32_t remain = (file_size = 0x2800000); // 40MB
275                                 void *tmp = calloc(1, SCSI_BUFFER_SIZE);
276                                 while(remain > 0) {
277                                         uint32_t length = min(remain, (uint32_t)SCSI_BUFFER_SIZE);
278                                         fio->Fwrite(tmp, length, 1);
279                                         remain -= length;
280                                 }
281                                 free(tmp);
282                                 #undef SCSI_BUFFER_SIZE
283                         }
284                         scsi_blocks[i] = file_size / BLOCK_SIZE;
285                         fio->Fclose();
286                 } else {
287                         scsi_blocks[i] = 0;
288                 }
289         }
290         delete fio;
291 }
292
293 void BIOS::reset()
294 {
295         for(int i = 0; i < MAX_DRIVE; i++) {
296                 access_fdd[i] = false;
297         }
298         access_scsi = false;
299         secnum = 1;
300         timeout = 0;
301 }
302
303 void BIOS::event_frame()
304 {
305         timeout++;
306 }
307
308 bool BIOS::bios_call_i86(uint32_t PC, uint16_t regs[], uint16_t sregs[], int32_t* ZeroFlag, int32_t* CarryFlag)
309 {
310         uint8_t *regs8 = (uint8_t *)regs;
311         int drv = AL & 0xf;
312         uint8_t buffer[BLOCK_SIZE * 4];
313         
314         if(PC == 0xfffc4) {
315                 // disk bios
316 #ifdef _DEBUG_LOG
317                 this->out_debug_log(_T("%6x\tDISK BIOS: AH=%2x,AL=%2x,CX=%4x,DX=%4x,BX=%4x,DS=%2x,DI=%2x\n"), get_cpu_pc(0), AH,AL,CX,DX,BX,DS,DI);
318 #endif
319                 if(AH == 2) {
320                         // drive status
321                         if((AL & 0xf0) == 0x20) {
322                                 // floppy
323                                 if(!(drv < MAX_DRIVE && disk[drv]->inserted)) {
324                                         AH = 0x80;
325                                         CX = ERR_FDD_NOTREADY;
326                                         *CarryFlag = 1;
327                                         return true;
328                                 }
329                                 AH = 0;
330                                 DL = 4;
331                                 if(disk[drv]->write_protected) {
332                                         DL |= 2;
333                                 }
334                                 CX = 0;
335                                 *CarryFlag = 0;
336                                 return true;
337                         }
338                         if((AL & 0xf0) == 0xb0) {
339                                 // scsi
340                                 if(!(drv < MAX_SCSI && scsi_blocks[drv])) {
341                                         AH = 0x80;
342                                         CX = ERR_SCSI_NOTCONNECTED;
343                                         *CarryFlag = 1;
344                                         return true;
345                                 }
346                                 AH = 0;
347                                 AL = (BLOCK_SIZE == 128) ? 0 : (BLOCK_SIZE == 256) ? 1 : (BLOCK_SIZE == 512) ? 2 : 3;
348                                 BX = scsi_blocks[drv] >> 16;
349                                 DX = scsi_blocks[drv] & 0xffff;
350                                 CX = 0;
351                                 *CarryFlag = 0;
352                                 return true;
353                         }
354                         AH = 2;
355                         *CarryFlag = 1;
356                         return true;
357                 } else if(AH == 3 || AH == 4) {
358                         // restore/seek
359                         if((AL & 0xf0) == 0x20) {
360                                 // floppy
361                                 if(!(drv < MAX_DRIVE && disk[drv]->inserted)) {
362                                         AH = 0x80;
363                                         CX = ERR_FDD_NOTREADY;
364                                         *CarryFlag = 1;
365                                         return true;
366                                 }
367                                 AH = 0;
368                                 CX = 0;
369                                 *CarryFlag = 0;
370                                 return true;
371                         }
372                         if((AL & 0xf0) == 0xb0) {
373                                 // scsi
374                                 if(!(drv < MAX_SCSI && scsi_blocks[drv])) {
375                                         AH = 0x80;
376                                         CX = ERR_SCSI_NOTCONNECTED;
377                                         *CarryFlag = 1;
378                                         return true;
379                                 }
380                                 AH = 0;
381                                 CX = 0;
382                                 *CarryFlag = 0;
383                                 return true;
384                         }
385                         AH = 2;
386                         *CarryFlag = 1;
387                         return true;
388                 } else if(AH == 5) {
389                         // read sectors
390                         if((AL & 0xf0) == 0x20) {
391                                 // floppy
392                                 if(!(drv < MAX_DRIVE && disk[drv]->inserted)) {
393                                         AH = 0x80;
394                                         CX = ERR_FDD_NOTREADY;
395                                         *CarryFlag = 1;
396                                         return true;
397                                 }
398                                 // get initial c/h/r
399                                 int ofs = DS * 16 + DI;
400                                 int trk = CX;
401                                 int hed = DH & 1;
402                                 int sct = DL;
403                                 while(BX > 0) {
404                                         // search sector
405                                         disk[drv]->get_track(trk, hed);
406                                         access_fdd[drv] = true;
407                                         secnum = sct;
408                                         if(!disk[drv]->get_sector(trk, hed, sct - 1)) {
409                                                 AH = 0x80;
410                                                 CX = ERR_FDD_NOTFOUND;
411                                                 *CarryFlag = 1;
412                                                 return true;
413                                         }
414                                         // check id crc error
415                                         if(disk[drv]->addr_crc_error && !disk[drv]->ignore_crc()) {
416                                                 AH = 0x80;
417                                                 CX = ERR_FDD_NOTFOUND | ERR_FDD_CRCERROR;
418                                                 *CarryFlag = 1;
419                                                 return true;
420                                         }
421                                         // check deleted mark
422                                         if(disk[drv]->deleted) {
423                                                 AH = 0x80;
424                                                 CX = ERR_FDD_DELETED;
425                                                 *CarryFlag = 1;
426                                                 return true;
427                                         }
428                                         // data transfer
429                                         for(int i = 0; i < disk[drv]->sector_size.sd; i++) {
430                                                 d_mem->write_data8(ofs++, disk[drv]->sector[i]);
431                                         }
432                                         BX--;
433                                         // check data crc error
434                                         if(disk[drv]->data_crc_error && !disk[drv]->ignore_crc()) {
435                                                 AH = 0x80;
436                                                 CX = ERR_FDD_CRCERROR;
437                                                 *CarryFlag = 1;
438                                                 return true;
439                                         }
440                                         // update c/h/r
441                                         if(++sct > disk[drv]->sector_num.sd) {
442                                                 sct = 1;
443                                                 if(++hed > 1) {
444                                                         hed = 0;
445                                                         ++trk;
446                                                 }
447                                         }
448                                 }
449                                 AH = 0;
450                                 CX = 0;
451                                 *CarryFlag = 0;
452                                 return true;
453                         }
454                         if((AL & 0xf0) == 0xb0) {
455                                 // scsi
456                                 if(!(drv < MAX_SCSI && scsi_blocks[drv])) {
457                                         AH = 0x80;
458                                         CX = ERR_SCSI_NOTCONNECTED;
459                                         *CarryFlag = 1;
460                                         return true;
461                                 }
462                                 FILEIO* fio = new FILEIO();
463                                 if(!fio->Fopen(create_local_path(_T("SCSI%d.DAT"), drv), FILEIO_READ_BINARY)) {
464                                         AH = 0x80;
465                                         CX = ERR_SCSI_NOTREADY;
466                                         *CarryFlag = 1;
467                                         delete fio;
468                                         return true;
469                                 }
470                                 // get params
471                                 int ofs = DS * 16 + DI;
472                                 int block = (CL << 16) | DX;
473                                 fio->Fseek(block * BLOCK_SIZE, FILEIO_SEEK_SET);
474                                 while(BX > 0) {
475                                         // check block
476                                         access_scsi = true;
477                                         if(!(block++ < scsi_blocks[drv])) {
478                                                 AH = 0x80;
479                                                 CX = ERR_SCSI_PARAMERROR;
480                                                 *CarryFlag = 1;
481                                                 fio->Fclose();
482                                                 delete fio;
483                                                 return true;
484                                         }
485                                         // data transfer
486                                         fio->Fread(buffer, BLOCK_SIZE, 1);
487                                         for(int i = 0; i < BLOCK_SIZE; i++) {
488                                                 d_mem->write_data8(ofs++, buffer[i]);
489                                         }
490                                         BX--;
491                                 }
492                                 AH = 0;
493                                 CX = 0;
494                                 *CarryFlag = 0;
495                                 fio->Fclose();
496                                 delete fio;
497                                 return true;
498                         }
499                         AH = 2;
500                         *CarryFlag = 1;
501                         return true;
502                 } else if(AH == 6) {
503                         // write sectors
504                         if((AL & 0xf0) == 0x20) {
505                                 // floppy
506                                 if(!(drv < MAX_DRIVE && disk[drv]->inserted)) {
507                                         AH = 0x80;
508                                         CX = ERR_FDD_NOTREADY;
509                                         *CarryFlag = 1;
510                                         return true;
511                                 }
512                                 if(disk[drv]->write_protected) {
513                                         AH = 0x80;
514                                         CX = ERR_FDD_PROTECTED;
515                                         *CarryFlag = 1;
516                                         return true;
517                                 }
518                                 // get initial c/h/r
519                                 int ofs = DS * 16 + DI;
520                                 int trk = CX;
521                                 int hed = DH & 1;
522                                 int sct = DL;
523                                 while(BX > 0) {
524                                         // search sector
525                                         disk[drv]->get_track(trk, hed);
526                                         access_fdd[drv] = true;
527                                         secnum = sct;
528                                         if(!disk[drv]->get_sector(trk, hed, sct - 1)) {
529                                                 AH = 0x80;
530                                                 CX = ERR_FDD_NOTFOUND;
531                                                 *CarryFlag = 1;
532                                                 return true;
533                                         }
534                                         // check id crc error
535                                         if(disk[drv]->addr_crc_error && !disk[drv]->ignore_crc()) {
536                                                 AH = 0x80;
537                                                 CX = ERR_FDD_NOTFOUND | ERR_FDD_CRCERROR;
538                                                 *CarryFlag = 1;
539                                                 return true;
540                                         }
541                                         // data transfer
542                                         for(int i = 0; i < disk[drv]->sector_size.sd; i++) {
543                                                 disk[drv]->sector[i] = d_mem->read_data8(ofs++);
544                                         }
545                                         BX--;
546                                         // clear deleted mark and data crc error
547                                         disk[drv]->set_deleted(false);
548                                         disk[drv]->set_data_crc_error(false);
549                                         // update c/h/r
550                                         if(++sct > disk[drv]->sector_num.sd) {
551                                                 sct = 1;
552                                                 if(++hed > 1) {
553                                                         hed = 0;
554                                                         ++trk;
555                                                 }
556                                         }
557                                 }
558                                 AH = 0;
559                                 CX = 0;
560                                 *CarryFlag = 0;
561                                 return true;
562                         }
563                         if((AL & 0xf0) == 0xb0) {
564                                 // scsi
565                                 if(!(drv < MAX_SCSI && scsi_blocks[drv])) {
566                                         AH = 0x80;
567                                         CX = ERR_SCSI_NOTCONNECTED;
568                                         *CarryFlag = 1;
569                                         return true;
570                                 }
571                                 FILEIO* fio = new FILEIO();
572                                 if(!fio->Fopen(create_local_path(_T("SCSI%d.DAT"), drv), FILEIO_READ_WRITE_BINARY)) {
573                                         AH = 0x80;
574                                         CX = ERR_SCSI_NOTREADY;
575                                         *CarryFlag = 1;
576                                         delete fio;
577                                         return true;
578                                 }
579                                 // get params
580                                 int ofs = DS * 16 + DI;
581                                 int block = (CL << 16) | DX;
582                                 fio->Fseek(block * BLOCK_SIZE, FILEIO_SEEK_SET);
583                                 while(BX > 0) {
584                                         // check block
585                                         access_scsi = true;
586                                         if(!(block++ < scsi_blocks[drv])) {
587                                                 AH = 0x80;
588                                                 CX = ERR_SCSI_PARAMERROR;
589                                                 *CarryFlag = 1;
590                                                 fio->Fclose();
591                                                 delete fio;
592                                                 return true;
593                                         }
594                                         // data transfer
595                                         for(int i = 0; i < BLOCK_SIZE; i++) {
596                                                 buffer[i] = d_mem->read_data8(ofs++);
597                                         }
598                                         fio->Fwrite(buffer, BLOCK_SIZE, 1);
599                                         BX--;
600                                 }
601                                 AH = 0;
602                                 CX = 0;
603                                 *CarryFlag = 0;
604                                 fio->Fclose();
605                                 delete fio;
606                                 return true;
607                         }
608                         AH = 2;
609                         *CarryFlag = 1;
610                         return true;
611                 } else if(AH == 7) {
612                         // verify sectors
613                         if((AL & 0xf0) == 0x20) {
614                                 // floppy
615                                 if(!(drv < MAX_DRIVE && disk[drv]->inserted)) {
616                                         AH = 0x80;
617                                         CX = ERR_FDD_NOTREADY;
618                                         *CarryFlag = 1;
619                                         return true;
620                                 }
621                                 // get initial c/h/r
622                                 int trk = CX;
623                                 int hed = DH & 1;
624                                 int sct = DL;
625                                 while(BX > 0) {
626                                         // search sector
627                                         disk[drv]->get_track(trk, hed);
628                                         access_fdd[drv] = true;
629                                         secnum = sct;
630                                         if(!disk[drv]->get_sector(trk, hed, sct - 1)) {
631                                                 AH = 0x80;
632                                                 CX = ERR_FDD_NOTFOUND;
633                                                 *CarryFlag = 1;
634                                                 return true;
635                                         }
636                                         // check id crc error
637                                         if(disk[drv]->addr_crc_error && !disk[drv]->ignore_crc()) {
638                                                 AH = 0x80;
639                                                 CX = ERR_FDD_NOTFOUND | ERR_FDD_CRCERROR;
640                                                 *CarryFlag = 1;
641                                                 return true;
642                                         }
643                                         // FIXME: verify
644                                         BX--;
645                                         // check data crc error
646                                         if(disk[drv]->data_crc_error && !disk[drv]->ignore_crc()) {
647                                                 AH = 0x80;
648                                                 CX = ERR_FDD_CRCERROR;
649                                                 *CarryFlag = 1;
650                                                 return true;
651                                         }
652                                         // update c/h/r
653                                         if(++sct > disk[drv]->sector_num.sd) {
654                                                 sct = 1;
655                                                 if(++hed > 1) {
656                                                         hed = 0;
657                                                         ++trk;
658                                                 }
659                                         }
660                                 }
661                                 AH = 0;
662                                 CX = 0;
663                                 *CarryFlag = 0;
664                                 return true;
665                         }
666                         if((AL & 0xf0) == 0xb0) {
667                                 // scsi
668                                 if(!(drv < MAX_SCSI && scsi_blocks[drv])) {
669                                         AH = 0x80;
670                                         CX = ERR_SCSI_NOTCONNECTED;
671                                         *CarryFlag = 1;
672                                         return true;
673                                 }
674                                 // get params
675                                 int block = (CL << 16) | DX;
676                                 while(BX > 0) {
677                                         // check block
678                                         access_scsi = true;
679                                         if(!(block++ < scsi_blocks[drv])) {
680                                                 AH = 0x80;
681                                                 CX = ERR_SCSI_PARAMERROR;
682                                                 *CarryFlag = 1;
683                                                 return true;
684                                         }
685                                         BX--;
686                                 }
687                                 AH = 0;
688                                 CX = 0;
689                                 *CarryFlag = 0;
690                                 return true;
691                         }
692                         AH = 2;
693                         *CarryFlag = 1;
694                         return true;
695                 } else if(AH == 8) {
696                         // reset hard drive controller
697                         AH = 0;
698                         CX = 0;
699                         *CarryFlag = 0;
700                         return true;
701                 } else if(AH == 9) {
702                         // read id
703                         if((AL & 0xf0) == 0x20) {
704                                 // floppy
705                                 if(!(drv < MAX_DRIVE && disk[drv]->inserted)) {
706                                         AH = 0x80;
707                                         CX = ERR_FDD_NOTREADY;
708                                         *CarryFlag = 1;
709                                         return true;
710                                 }
711                                 // get initial c/h
712                                 int ofs = DS * 16 + DI;
713                                 int trk = CX;
714                                 int hed = DH & 1;
715                                 // search sector
716                                 disk[drv]->get_track(trk, hed);
717                                 access_fdd[drv] = true;
718                                 if(++secnum > disk[drv]->sector_num.sd) {
719                                         secnum = 1;
720                                 }
721                                 if(!disk[drv]->get_sector(trk, hed, secnum - 1)) {
722                                         AH = 0x80;
723                                         CX = ERR_FDD_NOTFOUND;
724                                         *CarryFlag = 1;
725                                         return true;
726                                 }
727                                 // data transfer
728                                 for(int i = 0; i < 6; i++) {
729                                         d_mem->write_data8(ofs++, disk[drv]->id[i]);
730                                 }
731                                 // check id crc error
732                                 if(disk[drv]->addr_crc_error && !disk[drv]->ignore_crc()) {
733                                         AH = 0x80;
734                                         CX = ERR_FDD_CRCERROR;
735                                         *CarryFlag = 1;
736                                         return true;
737                                 }
738                                 AH = 0;
739                                 CX = 0;
740                                 *CarryFlag = 0;
741                                 return true;
742                         }
743                         AH = 2;
744                         *CarryFlag = 1;
745                         return true;
746                 } else if(AH == 0xa) {
747                         // format track
748                         if((AL & 0xf0) == 0x20) {
749                                 // floppy
750                                 if(!(drv < MAX_DRIVE && disk[drv]->inserted)) {
751                                         AH = 0x80;
752                                         CX = ERR_FDD_NOTREADY;
753                                         *CarryFlag = 1;
754                                         return true;
755                                 }
756                                 // get initial c/h
757                                 int ofs = DS * 16 + DI;
758                                 int trk = CX;
759                                 int hed = DH & 1;
760                                 // format track
761                                 disk[drv]->format_track(trk, hed);
762                                 access_fdd[drv] = true;
763                                 bool id_written = false;
764                                 bool sector_found = false;
765                                 int sector_length, sector_index;
766                                 for(int index = 0; index < disk[drv]->get_track_size(); index++) {
767                                         uint8_t datareg = d_mem->read_data8(ofs++);
768                                         if(datareg == 0xf5) {
769                                                 // write a1h in missing clock
770                                         } else if(datareg == 0xf6) {
771                                                 // write c2h in missing clock
772                                         } else if(datareg == 0xf7) {
773                                                 // write crc
774                                                 if(!id_written) {
775                                                         // insert new sector with data crc error
776 write_id:
777                                                         id_written = true;
778                                                         sector_found = false;
779                                                         uint8_t c = disk[drv]->track[index - 4];
780                                                         uint8_t h = disk[drv]->track[index - 3];
781                                                         uint8_t r = disk[drv]->track[index - 2];
782                                                         uint8_t n = disk[drv]->track[index - 1];
783                                                         sector_length = 0x80 << (n & 3);
784                                                         sector_index = 0;
785                                                         disk[drv]->insert_sector(c, h, r, n, false, true, 0xe5, sector_length);
786                                                 } else if(sector_found) {
787                                                         // clear data crc error if all sector data are written
788                                                         disk[drv]->set_data_crc_error(false);
789                                                         id_written = false;
790                                                 } else {
791                                                         // data mark of current sector is not written
792                                                         disk[drv]->set_data_mark_missing();
793                                                         goto write_id;
794                                                 }
795                                         } else if(id_written) {
796                                                 if(sector_found) {
797                                                         // sector data
798                                                         if(sector_index < sector_length) {
799                                                                 disk[drv]->sector[sector_index] = datareg;
800                                                         }
801                                                         sector_index++;
802                                                 } else if(datareg == 0xf8 || datareg == 0xfb) {
803                                                         // data mark
804                                                         disk[drv]->set_deleted(datareg == 0xf8);
805                                                         sector_found = true;
806                                                 }
807                                         }
808                                         disk[drv]->track[index] = datareg;
809                                 }
810                                 AH = 0;
811                                 CX = 0;
812                                 *CarryFlag = 0;
813                                 return true;
814                         }
815                         AH = 2;
816                         *CarryFlag = 1;
817                         return true;
818                 } else if(AH == 0xd) {
819                         // read error
820                         AH = 0;
821                         CX = 0;
822                         *CarryFlag = 0;
823                         return true;
824                 } else if(AH == 0xe) {
825                         // disk change ???
826                         if((AL & 0xf0) == 0x20) {
827                                 // floppy
828                                 if(!(drv < MAX_DRIVE && disk[drv]->inserted)) {
829                                         AH = 0;
830                                         CX = 0;
831                                         DL = 1;
832                                         *CarryFlag = 0;
833                                         return true;
834                                 }
835                                 AH = 0;
836                                 CX = 0;
837                                 DL = disk[drv]->changed ? 1 : 0;
838                                 disk[drv]->changed = false;
839                                 *CarryFlag = 0;
840                                 return true;
841                         }
842                         if((AL & 0xf0) == 0xb0) {
843                                 // scsi
844                                 if(!(drv < MAX_SCSI && scsi_blocks[drv])) {
845                                         AH = 3; // ???
846                                         CX = 0;
847                                         *CarryFlag = 1;
848                                         return true;
849                                 }
850                                 AH = 0;
851                                 CX = 0;
852                                 *CarryFlag = 0;
853                                 return true;
854                         }
855                         AH = 2;
856                         CX = 0;
857                         *CarryFlag = 1;
858                         return true;
859                 } else if(AH == 0xfa) {
860                         // unknown
861                         if((AL & 0xf0) == 0x20) {
862                                 // floppy
863                                 AH = 1;
864                                 CX = 0;
865                                 *CarryFlag = 1;
866                                 return true;
867                         }
868                         if((AL & 0xf0) == 0xb0) {
869                                 // scsi
870                                 if(!(drv < MAX_SCSI && scsi_blocks[drv])) {
871                                         AH = 0x80;
872                                         CX = ERR_SCSI_NOTCONNECTED;
873                                         *CarryFlag = 1;
874                                         return true;
875                                 }
876                                 AH = 0;
877                                 CX = 0;
878                                 *CarryFlag = 0;
879                                 return true;
880                         }
881                         AH = 2;
882                         *CarryFlag = 1;
883                         return true;
884                 } else if(AH == 0xfd) {
885                         // unknown
886                         if((AL & 0xf0) == 0x20) {
887                                 // floppy
888                                 AH = 1;
889                                 CX = 0;
890                                 *CarryFlag = 1;
891                                 return true;
892                         }
893                         if((AL & 0xf0) == 0xb0) {
894                                 // scsi
895                                 if(!(drv < MAX_SCSI && scsi_blocks[drv])) {
896                                         AH = 0;
897                                         CX = 0x200;     // ???
898                                         *CarryFlag = 0;
899                                         return true;
900                                 }
901                                 AH = 2;
902                                 CX = 0;
903                                 *CarryFlag = 1;
904                                 return true;
905                         }
906                         AH = 2;
907                         CX = 0;
908                         *CarryFlag = 1;
909                         return true;
910                 } else if(AH == 0x80) {
911                         // pseudo bios: init i/o
912                         for(int i = 0;; i++) {
913                                 if(iotable[i][0] < 0) {
914                                         break;
915                                 }
916                                 d_io->write_io8(iotable[i][0], iotable[i][1]);
917                         }
918                         // init cmos
919                         memset(cmos, 0, CMOS_SIZE);
920                         memcpy(cmos, cmos_t, sizeof(cmos_t));
921                         memcpy(cmos + CMOS_SIZE - sizeof(cmos_b), cmos_b, sizeof(cmos_b));
922                         // init int vector
923                         for(int i = 0, ofs = 0; i < 256; i++) {
924                                 // int vector = ffff:0008
925                                 d_mem->write_data16(ofs + 0, 0x0008);
926                                 d_mem->write_data16(ofs + 2, 0xffff);
927                                 ofs += 4;
928                         }
929                         // init screen
930                         memset(vram, 0, VRAM_SIZE);
931 #ifdef _FMR60
932                         memset(cvram, 0, 0x2000);
933                         memset(avram, 0, 0x2000);
934 #else
935                         memset(cvram, 0, 0x1000);
936                         memset(kvram, 0, 0x1000);
937                         memcpy(cvram + 0xf00, msg_c, sizeof(msg_c));
938                         memcpy(kvram + 0xf00, msg_k, sizeof(msg_k));
939 #endif
940                         *CarryFlag = 0;
941                         return true;
942                 } else if(AH == 0x81) {
943                         // pseudo bios: boot from fdd #0
944                         *ZeroFlag = (timeout > (int)(FRAMES_PER_SEC * 4));
945                         if(!disk[0]->inserted) {
946                                 *CarryFlag = 1;
947                                 return true;
948                         }
949                         // load ipl
950                         disk[0]->get_track(0, 0);
951                         access_fdd[0] = true;
952                         if(!disk[0]->get_sector(0, 0, 0)) {
953                                 *CarryFlag = 1;
954                                 return true;
955                         }
956                         for(int i = 0; i < disk[0]->sector_size.sd; i++) {
957                                 buffer[i] = disk[0]->sector[i];
958                         }
959                         // check ipl
960                         if(!(buffer[0] == 'I' && buffer[1] == 'P' && buffer[2] == 'L' && buffer[3] == IPL_ID)) {
961                                 *CarryFlag = 1;
962                                 return true;
963                         }
964                         // data transfer
965                         for(int i = 0; i < disk[0]->sector_size.sd; i++) {
966                                 d_mem->write_data8(0xb0000 + i, buffer[i]);
967                         }
968                         // clear screen
969 #ifdef _FMR60
970                         memset(cvram, 0, 0x2000);
971                         memset(avram, 0, 0x2000);
972 #else
973                         memset(cvram, 0, 0x1000);
974                         memset(kvram, 0, 0x1000);
975 #endif
976                         // set result
977                         AX = 0xff;
978                         CX = 0;
979                         BX = 2;
980                         *ZeroFlag = 1;
981                         *CarryFlag = 0;
982                         return true;
983                 } else if(AH == 0x82) {
984                         // pseudo bios: boot from scsi-hdd #0
985                         timeout = 0;
986                         if(!scsi_blocks[0]) {
987                                 *CarryFlag = 1;
988                                 return true;
989                         }
990                         FILEIO* fio = new FILEIO();
991                         if(!fio->Fopen(create_local_path(_T("SCSI%d.DAT"), drv), FILEIO_READ_BINARY)) {
992                                 *CarryFlag = 1;
993                                 delete fio;
994                                 return true;
995                         }
996                         // load ipl
997                         access_scsi = true;
998                         fio->Fread(buffer, BLOCK_SIZE * 4, 1);
999                         fio->Fclose();
1000                         delete fio;
1001                         // check ipl
1002                         if(!(buffer[0] == 'I' && buffer[1] == 'P' && buffer[2] == 'L' && buffer[3] == IPL_ID)) {
1003                                 *CarryFlag = 1;
1004                                 return true;
1005                         }
1006                         // data transfer
1007                         for(int i = 0; i < BLOCK_SIZE * 4; i++) {
1008                                 d_mem->write_data8(0xb0000 + i, buffer[i]);
1009                         }
1010                         // clear screen
1011 #ifdef _FMR60
1012                         memset(cvram, 0, 0x2000);
1013                         memset(avram, 0, 0x2000);
1014 #else
1015                         memset(cvram, 0, 0x1000);
1016                         memset(kvram, 0, 0x1000);
1017 #endif
1018                         // set result
1019                         AX = 0xffff;
1020                         CX = 0;
1021                         BX = 1;
1022                         *ZeroFlag = 1;
1023                         *CarryFlag = 0;
1024                         return true;
1025                 }
1026         } else if(PC == 0xfffc9) {
1027                 // cmos
1028 #ifdef _DEBUG_LOG
1029                 this->out_debug_log(_T("%6x\tCMOS BIOS: AH=%2x,AL=%2x,CX=%4x,DX=%4x,BX=%4x,DS=%2x,DI=%2x\n"), get_cpu_pc(0), AH,AL,CX,DX,BX,DS,DI);
1030 #endif
1031                 if(AH == 0) {
1032                         // init cmos
1033                         memcpy(cmos, cmos_t, sizeof(cmos_t));
1034                         memcpy(cmos + CMOS_SIZE - sizeof(cmos_b), cmos_b, sizeof(cmos_b));
1035                 } else if(AH == 5) {
1036                         // get $a2
1037                         BX = cmos[0xa2] | (cmos[0xa3] << 8);
1038                 } else if(AH == 10) {
1039                         // memory to cmos
1040                         int block = AL * 10;
1041                         int len = cmos[block + 6] | (cmos[block + 7] << 8);
1042                         int dst = cmos[block + 8] | (cmos[block + 9] << 8);
1043                         int src = DS * 16 + DI;
1044                         for(int i = 0; i < len; i++) {
1045                                 cmos[dst++] = d_mem->read_data8(src++);
1046                         }
1047                 } else if(AH == 11) {
1048                         // cmos to memory
1049                         int block = AL * 10;
1050                         int len = cmos[block + 6] | (cmos[block + 7] << 8);
1051                         int src = cmos[block + 8] | (cmos[block + 9] << 8);
1052                         int dst = DS * 16 + DI;
1053                         for(int i = 0; i < len; i++) {
1054                                 d_mem->write_data8(dst++, cmos[src++]);
1055                         }
1056                 } else if(AH == 20) {
1057                         // check block header
1058                         BX = 0;
1059                 }
1060                 AH = 0;
1061                 *CarryFlag = 0;
1062                 return true;
1063         } else if(PC == 0xfffd3) {
1064                 // wait
1065 #ifdef _DEBUG_LOG
1066                 this->out_debug_log(_T("%6x\tWAIT BIOS: AH=%2x,AL=%2x,CX=%4x,DX=%4x,BX=%4x,DS=%2x,DI=%2x\n"), get_cpu_pc(0), AH,AL,CX,DX,BX,DS,DI);
1067 #endif
1068                 *CarryFlag = 0;
1069                 return true;
1070         }
1071         return false;
1072 }
1073
1074 bool BIOS::bios_int_i86(int intnum, uint16_t regs[], uint16_t sregs[], int32_t* ZeroFlag, int32_t* CarryFlag)
1075 {
1076         uint8_t *regs8 = (uint8_t *)regs;
1077         
1078         if(intnum == 0x93) {
1079                 // disk bios
1080                 return bios_call_i86(0xfffc4, regs, sregs, ZeroFlag, CarryFlag);
1081         }
1082         return false;
1083 }
1084
1085 uint32_t BIOS::read_signal(int ch)
1086 {
1087         // get access status
1088         uint32_t stat = 0;
1089         for(int i = 0; i < MAX_DRIVE; i++) {
1090                 if(access_fdd[i]) {
1091                         stat |= 1 << i;
1092                 }
1093                 access_fdd[i] = false;
1094         }
1095         if(access_scsi) {
1096                 stat |= 0x10;
1097         }
1098         access_scsi = false;
1099         return stat;
1100 }
1101
1102 #define STATE_VERSION   3
1103
1104 void BIOS::save_state(FILEIO* state_fio)
1105 {
1106         state_fio->FputUint32(STATE_VERSION);
1107         state_fio->FputInt32(this_device_id);
1108         
1109         for(int i = 0; i < MAX_DRIVE; i++) {
1110                 disk[i]->save_state(state_fio);
1111         }
1112         state_fio->FputInt32(secnum);
1113         state_fio->FputInt32(timeout);
1114 }
1115
1116 bool BIOS::load_state(FILEIO* state_fio)
1117 {
1118         if(state_fio->FgetUint32() != STATE_VERSION) {
1119                 return false;
1120         }
1121         if(state_fio->FgetInt32() != this_device_id) {
1122                 return false;
1123         }
1124         for(int i = 0; i < MAX_DRIVE; i++) {
1125                 if(!disk[i]->load_state(state_fio)) {
1126                         return false;
1127                 }
1128         }
1129         secnum = state_fio->FgetInt32();
1130         timeout = state_fio->FgetInt32();
1131         return true;
1132 }
1133