OSDN Git Service

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