1 /*EGA emulation*/
2 #include <stdlib.h>
3 #include "ibm.h"
4 #include "device.h"
5 #include "io.h"
6 #include "mem.h"
7 #include "rom.h"
8 #include "timer.h"
9 #include "video.h"
10 #include "vid_ega.h"
11 
12 extern uint8_t edatlookup[4][4];
13 
14 static uint8_t ega_rotate[8][256];
15 
16 static uint32_t pallook16[256], pallook64[256];
17 
18 /*3C2 controls default mode on EGA. On VGA, it determines monitor type (mono or colour)*/
19 int egaswitchread,egaswitches=9; /*7=CGA mode (200 lines), 9=EGA mode (350 lines), 8=EGA mode (200 lines)*/
20 
ega_out(uint16_t addr,uint8_t val,void * p)21 void ega_out(uint16_t addr, uint8_t val, void *p)
22 {
23         ega_t *ega = (ega_t *)p;
24         int c;
25         uint8_t o, old;
26 
27         if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1))
28                 addr ^= 0x60;
29 
30         switch (addr)
31         {
32                 case 0x3c0:
33                 if (!ega->attrff)
34                    ega->attraddr = val & 31;
35                 else
36                 {
37                         ega->attrregs[ega->attraddr & 31] = val;
38                         if (ega->attraddr < 16)
39                                 fullchange = changeframecount;
40                         if (ega->attraddr == 0x10 || ega->attraddr == 0x14 || ega->attraddr < 0x10)
41                         {
42                                 for (c = 0; c < 16; c++)
43                                 {
44                                         if (ega->attrregs[0x10] & 0x80) ega->egapal[c] = (ega->attrregs[c] &  0xf) | ((ega->attrregs[0x14] & 0xf) << 4);
45                                         else                            ega->egapal[c] = (ega->attrregs[c] & 0x3f) | ((ega->attrregs[0x14] & 0xc) << 4);
46                                 }
47                         }
48                 }
49                 ega->attrff ^= 1;
50                 break;
51                 case 0x3c2:
52                 egaswitchread = val & 0xc;
53                 ega->vres = !(val & 0x80);
54                 ega->pallook = ega->vres ? pallook16 : pallook64;
55                 ega->vidclock = val & 4; /*printf("3C2 write %02X\n",val);*/
56                 ega->miscout=val;
57                 break;
58                 case 0x3c4:
59                 ega->seqaddr = val;
60                 break;
61                 case 0x3c5:
62                 o = ega->seqregs[ega->seqaddr & 0xf];
63                 ega->seqregs[ega->seqaddr & 0xf] = val;
64                 if (o != val && (ega->seqaddr & 0xf) == 1)
65                         ega_recalctimings(ega);
66                 switch (ega->seqaddr & 0xf)
67                 {
68                         case 1:
69                         if (ega->scrblank && !(val & 0x20))
70                                 fullchange = 3;
71                         ega->scrblank = (ega->scrblank & ~0x20) | (val & 0x20);
72                         break;
73                         case 2:
74                         ega->writemask = val & 0xf;
75                         break;
76                         case 3:
77                         ega->charsetb = (((val >> 2) & 3) * 0x10000) + 2;
78                         ega->charseta = ((val & 3)        * 0x10000) + 2;
79                         break;
80                         case 4:
81                         ega->chain2_write = !(val & 4);
82                         break;
83                 }
84                 break;
85                 case 0x3ce:
86                 ega->gdcaddr = val;
87                 break;
88                 case 0x3cf:
89                 ega->gdcreg[ega->gdcaddr & 15] = val;
90                 switch (ega->gdcaddr & 15)
91                 {
92                         case 2:
93                         ega->colourcompare = val;
94                         break;
95                         case 4:
96                         ega->readplane = val & 3;
97                         break;
98                         case 5:
99                         ega->writemode = val & 3;
100                         ega->readmode = val & 8;
101                         ega->chain2_read = val & 0x10;
102                         break;
103                         case 6:
104 //                                pclog("Write mapping %02X\n", val);
105                         switch (val & 0xc)
106                         {
107                                 case 0x0: /*128k at A0000*/
108                                 mem_mapping_set_addr(&ega->mapping, 0xa0000, 0x20000);
109                                 break;
110                                 case 0x4: /*64k at A0000*/
111                                 mem_mapping_set_addr(&ega->mapping, 0xa0000, 0x10000);
112                                 break;
113                                 case 0x8: /*32k at B0000*/
114                                 mem_mapping_set_addr(&ega->mapping, 0xb0000, 0x08000);
115                                 break;
116                                 case 0xC: /*32k at B8000*/
117                                 mem_mapping_set_addr(&ega->mapping, 0xb8000, 0x08000);
118                                 break;
119                         }
120                         break;
121                         case 7:
122                         ega->colournocare = val;
123                         break;
124                 }
125                 break;
126                 case 0x3d4:
127                         pclog("Write 3d4 %02X  %04X:%04X\n", val, CS, cpu_state.pc);
128                 ega->crtcreg = val & 31;
129                 return;
130                 case 0x3d5:
131                         pclog("Write 3d5 %02X %02X %02X\n", ega->crtcreg, val, ega->crtc[0x11]);
132 //                if (ega->crtcreg == 1 && val == 0x14)
133 //                        fatal("Here\n");
134                 if (ega->crtcreg <= 7 && ega->crtc[0x11] & 0x80) return;
135                 old = ega->crtc[ega->crtcreg];
136                 ega->crtc[ega->crtcreg] = val;
137                 if (old != val)
138                 {
139                         if (ega->crtcreg < 0xe || ega->crtcreg > 0x10)
140                         {
141                                 fullchange = changeframecount;
142                                 ega_recalctimings(ega);
143                         }
144                 }
145                 break;
146         }
147 }
148 
ega_in(uint16_t addr,void * p)149 uint8_t ega_in(uint16_t addr, void *p)
150 {
151         ega_t *ega = (ega_t *)p;
152 
153         if (addr != 0x3da && addr != 0x3ba)
154                 pclog("ega_in %04X\n", addr);
155         if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1))
156                 addr ^= 0x60;
157 
158         switch (addr)
159         {
160                 case 0x3c0:
161                 return ega->attraddr;
162                 case 0x3c1:
163                 return ega->attrregs[ega->attraddr];
164                 case 0x3c2:
165 //                printf("Read egaswitch %02X %02X %i\n",egaswitchread,egaswitches,VGA);
166                 switch (egaswitchread)
167                 {
168                         case 0xc: return (egaswitches & 1) ? 0x10 : 0;
169                         case 0x8: return (egaswitches & 2) ? 0x10 : 0;
170                         case 0x4: return (egaswitches & 4) ? 0x10 : 0;
171                         case 0x0: return (egaswitches & 8) ? 0x10 : 0;
172                 }
173                 break;
174                 case 0x3c4:
175                 return ega->seqaddr;
176                 case 0x3c5:
177                 return ega->seqregs[ega->seqaddr & 0xf];
178                 case 0x3ce:
179                 return ega->gdcaddr;
180                 case 0x3cf:
181                 return ega->gdcreg[ega->gdcaddr & 0xf];
182                 case 0x3d4:
183                 return ega->crtcreg;
184                 case 0x3d5:
185                 return ega->crtc[ega->crtcreg];
186                 case 0x3da:
187                 ega->attrff = 0;
188                 ega->stat ^= 0x30; /*Fools IBM EGA video BIOS self-test*/
189                 return ega->stat;
190         }
191 //        printf("Bad EGA read %04X %04X:%04X\n",addr,cs>>4,pc);
192         return 0xff;
193 }
194 
ega_recalctimings(ega_t * ega)195 void ega_recalctimings(ega_t *ega)
196 {
197 	double _dispontime, _dispofftime, disptime;
198         double crtcconst;
199 
200         ega->vtotal = ega->crtc[6];
201         ega->dispend = ega->crtc[0x12];
202         ega->vsyncstart = ega->crtc[0x10];
203         ega->split = ega->crtc[0x18];
204 
205         if (ega->crtc[7] & 1)  ega->vtotal |= 0x100;
206         if (ega->crtc[7] & 32) ega->vtotal |= 0x200;
207         ega->vtotal++;
208 
209         if (ega->crtc[7] & 2)  ega->dispend |= 0x100;
210         if (ega->crtc[7] & 64) ega->dispend |= 0x200;
211         ega->dispend++;
212 
213         if (ega->crtc[7] & 4)   ega->vsyncstart |= 0x100;
214         if (ega->crtc[7] & 128) ega->vsyncstart |= 0x200;
215         ega->vsyncstart++;
216 
217         if (ega->crtc[7] & 0x10) ega->split |= 0x100;
218         if (ega->crtc[9] & 0x40) ega->split |= 0x200;
219         ega->split+=2;
220 
221         ega->hdisp = ega->crtc[1];
222         ega->hdisp++;
223 
224         ega->rowoffset = ega->crtc[0x13];
225 
226         printf("Recalc! %i %i %i %i   %i %02X\n", ega->vtotal, ega->dispend, ega->vsyncstart, ega->split, ega->hdisp, ega->attrregs[0x16]);
227 
228         if (ega->vidclock) crtcconst = (ega->seqregs[1] & 1) ? MDACONST : (MDACONST * (9.0 / 8.0));
229         else               crtcconst = (ega->seqregs[1] & 1) ? CGACONST : (CGACONST * (9.0 / 8.0));
230 
231         disptime = ega->crtc[0] + 2;
232         _dispontime = ega->crtc[1] + 1;
233 
234         printf("Disptime %f dispontime %f hdisp %i\n", disptime, _dispontime, ega->crtc[1] * 8);
235         if (ega->seqregs[1] & 8)
236         {
237                 disptime*=2;
238                 _dispontime*=2;
239         }
240         _dispofftime = disptime - _dispontime;
241         _dispontime  *= crtcconst;
242         _dispofftime *= crtcconst;
243 
244 	ega->dispontime  = (int)(_dispontime  * (1 << TIMER_SHIFT));
245 	ega->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT));
246         pclog("dispontime %i (%f)  dispofftime %i (%f)\n", ega->dispontime, (float)ega->dispontime / (1 << TIMER_SHIFT),
247                                                            ega->dispofftime, (float)ega->dispofftime / (1 << TIMER_SHIFT));
248 //        printf("EGA horiz total %i display end %i clock rate %i vidclock %i %i\n",crtc[0],crtc[1],egaswitchread,vidclock,((ega3c2>>2)&3) | ((tridentnewctrl2<<2)&4));
249 //        printf("EGA vert total %i display end %i max row %i vsync %i\n",ega_vtotal,ega_dispend,(crtc[9]&31)+1,ega_vsyncstart);
250 //        printf("total %f on %f cycles off %f cycles frame %f sec %f %02X\n",disptime*crtcconst,dispontime,dispofftime,(dispontime+dispofftime)*ega_vtotal,(dispontime+dispofftime)*ega_vtotal*70,seqregs[1]);
251 }
252 
ega_draw_text(ega_t * ega)253 static void ega_draw_text(ega_t *ega)
254 {
255         int x, xx;
256 
257         for (x = 0; x < ega->hdisp; x++)
258         {
259                 int drawcursor = ((ega->ma == ega->ca) && ega->con && ega->cursoron);
260                 uint8_t chr  = ega->vram[(ega->ma << 1) & ega->vrammask];
261                 uint8_t attr = ega->vram[((ega->ma << 1) + 1) & ega->vrammask];
262                 uint8_t dat;
263                 uint32_t fg, bg;
264                 uint32_t charaddr;
265 
266                 if (attr & 8)
267                         charaddr = ega->charsetb + (chr * 128);
268                 else
269                         charaddr = ega->charseta + (chr * 128);
270 
271                 if (drawcursor)
272                 {
273                         bg = ega->pallook[ega->egapal[attr & 15]];
274                         fg = ega->pallook[ega->egapal[attr >> 4]];
275                 }
276                 else
277                 {
278                         fg = ega->pallook[ega->egapal[attr & 15]];
279                         bg = ega->pallook[ega->egapal[attr >> 4]];
280                         if (attr & 0x80 && ega->attrregs[0x10] & 8)
281                         {
282                                 bg = ega->pallook[ega->egapal[(attr >> 4) & 7]];
283                                 if (ega->blink & 16)
284                                         fg = bg;
285                         }
286                 }
287 
288                 dat = ega->vram[charaddr + (ega->sc << 2)];
289                 if (ega->seqregs[1] & 8)
290                 {
291                         if (ega->seqregs[1] & 1)
292                         {
293                                 for (xx = 0; xx < 8; xx++)
294                                         ((uint32_t *)buffer32->line[ega->displine])[((x << 4) + 32 + (xx << 1)) & 2047] =
295                                         ((uint32_t *)buffer32->line[ega->displine])[((x << 4) + 33 + (xx << 1)) & 2047] = (dat & (0x80 >> xx)) ? fg : bg;
296                         }
297                         else
298                         {
299                                 for (xx = 0; xx < 8; xx++)
300                                         ((uint32_t *)buffer32->line[ega->displine])[((x * 18) + 32 + (xx << 1)) & 2047] =
301                                         ((uint32_t *)buffer32->line[ega->displine])[((x * 18) + 33 + (xx << 1)) & 2047] = (dat & (0x80 >> xx)) ? fg : bg;
302                                 if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4))
303                                         ((uint32_t *)buffer32->line[ega->displine])[((x * 18) + 32 + 16) & 2047] =
304                                         ((uint32_t *)buffer32->line[ega->displine])[((x * 18) + 32 + 17) & 2047] = bg;
305                                 else
306                                         ((uint32_t *)buffer32->line[ega->displine])[((x * 18) + 32 + 16) & 2047] =
307                                         ((uint32_t *)buffer32->line[ega->displine])[((x * 18) + 32 + 17) & 2047] = (dat & 1) ? fg : bg;
308                         }
309                 }
310                 else
311                 {
312                         if (ega->seqregs[1] & 1)
313                         {
314                                 for (xx = 0; xx < 8; xx++)
315                                         ((uint32_t *)buffer32->line[ega->displine])[((x << 3) + 32 + xx) & 2047] = (dat & (0x80 >> xx)) ? fg : bg;
316                         }
317                         else
318                         {
319                                 for (xx = 0; xx < 8; xx++)
320                                         ((uint32_t *)buffer32->line[ega->displine])[((x * 9) + 32 + xx) & 2047] = (dat & (0x80 >> xx)) ? fg : bg;
321                                 if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4))
322                                         ((uint32_t *)buffer32->line[ega->displine])[((x * 9) + 32 + 8) & 2047] = bg;
323                                 else
324                                         ((uint32_t *)buffer32->line[ega->displine])[((x * 9) + 32 + 8) & 2047] = (dat & 1) ? fg : bg;
325                         }
326                 }
327                 ega->ma += 4;
328                 ega->ma &= ega->vrammask;
329         }
330 }
331 
ega_draw_2bpp(ega_t * ega)332 static void ega_draw_2bpp(ega_t *ega)
333 {
334         int x;
335         int offset = ((8 - ega->scrollcache) << 1) + 16;
336 
337         for (x = 0; x <= ega->hdisp; x++)
338         {
339                 uint8_t edat[2];
340                 uint32_t addr = ega->ma;
341 
342                 if (!(ega->crtc[0x17] & 0x40))
343                 {
344                         addr = (addr << 1) & ega->vrammask;
345                         addr &= ~7;
346                         if ((ega->crtc[0x17] & 0x20) && (ega->ma & 0x20000))
347                                 addr |= 4;
348                         if (!(ega->crtc[0x17] & 0x20) && (ega->ma & 0x8000))
349                                 addr |= 4;
350                 }
351                 if (!(ega->crtc[0x17] & 0x01))
352                         addr = (addr & ~0x8000) | ((ega->sc & 1) ? 0x8000 : 0);
353                 if (!(ega->crtc[0x17] & 0x02))
354                         addr = (addr & ~0x10000) | ((ega->sc & 2) ? 0x10000 : 0);
355 
356                 edat[0] = ega->vram[addr];
357                 edat[1] = ega->vram[addr | 0x1];
358                 if (ega->seqregs[1] & 4)
359                         ega->ma += 2;
360                 else
361                         ega->ma += 4;
362 
363                 ega->ma &= ega->vrammask;
364 
365                 ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 14 + offset]=  ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 15 + offset] = ega->pallook[ega->egapal[edat[1] & 3]];
366                 ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 12 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 13 + offset] = ega->pallook[ega->egapal[(edat[1] >> 2) & 3]];
367                 ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 10 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 11 + offset] = ega->pallook[ega->egapal[(edat[1] >> 4) & 3]];
368                 ((uint32_t *)buffer32->line[ega->displine])[(x << 4) +  8 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) +  9 + offset] = ega->pallook[ega->egapal[(edat[1] >> 6) & 3]];
369                 ((uint32_t *)buffer32->line[ega->displine])[(x << 4) +  6 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) +  7 + offset] = ega->pallook[ega->egapal[(edat[0] >> 0) & 3]];
370                 ((uint32_t *)buffer32->line[ega->displine])[(x << 4) +  4 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) +  5 + offset] = ega->pallook[ega->egapal[(edat[0] >> 2) & 3]];
371                 ((uint32_t *)buffer32->line[ega->displine])[(x << 4) +  2 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) +  3 + offset] = ega->pallook[ega->egapal[(edat[0] >> 4) & 3]];
372                 ((uint32_t *)buffer32->line[ega->displine])[(x << 4) +      offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) +  1 + offset] = ega->pallook[ega->egapal[(edat[0] >> 6) & 3]];
373         }
374 }
375 
ega_draw_4bpp_lowres(ega_t * ega)376 static void ega_draw_4bpp_lowres(ega_t *ega)
377 {
378         int x;
379         int offset = ((8 - ega->scrollcache) << 1) + 16;
380 
381         for (x = 0; x <= ega->hdisp; x++)
382         {
383                 uint8_t edat[4];
384                 uint8_t dat;
385                 uint32_t addr = ega->ma;
386                 int oddeven = 0;
387 
388                 if (!(ega->crtc[0x17] & 0x40))
389                 {
390                         addr = (addr << 1) & ega->vrammask;
391                         if (ega->seqregs[1] & 4)
392                                 oddeven = (addr & 4) ? 1 : 0;
393                         addr &= ~7;
394                         if ((ega->crtc[0x17] & 0x20) && (ega->ma & 0x20000))
395                                 addr |= 4;
396                         if (!(ega->crtc[0x17] & 0x20) && (ega->ma & 0x8000))
397                                 addr |= 4;
398                 }
399                 if (!(ega->crtc[0x17] & 0x01))
400                         addr = (addr & ~0x8000) | ((ega->sc & 1) ? 0x8000 : 0);
401                 if (!(ega->crtc[0x17] & 0x02))
402                         addr = (addr & ~0x10000) | ((ega->sc & 2) ? 0x10000 : 0);
403 
404                 if (ega->seqregs[1] & 4)
405                 {
406                         edat[0] = ega->vram[addr | oddeven];
407                         edat[2] = ega->vram[addr | oddeven | 0x2];
408                         edat[1] = edat[3] = 0;
409                         ega->ma += 2;
410                 }
411                 else
412                 {
413                         edat[0] = ega->vram[addr];
414                         edat[1] = ega->vram[addr | 0x1];
415                         edat[2] = ega->vram[addr | 0x2];
416                         edat[3] = ega->vram[addr | 0x3];
417                         ega->ma += 4;
418                 }
419                 ega->ma &= ega->vrammask;
420 
421                 dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2);
422                 ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 14 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 15 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]];
423                 ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 12 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 13 + offset] = ega->pallook[ega->egapal[(dat >> 4)  & ega->attrregs[0x12]]];
424                 dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2);
425                 ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 10 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 11 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]];
426                 ((uint32_t *)buffer32->line[ega->displine])[(x << 4) +  8 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) +  9 + offset] = ega->pallook[ega->egapal[(dat >> 4)  & ega->attrregs[0x12]]];
427                 dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2);
428                 ((uint32_t *)buffer32->line[ega->displine])[(x << 4) +  6 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) +  7 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]];
429                 ((uint32_t *)buffer32->line[ega->displine])[(x << 4) +  4 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) +  5 + offset] = ega->pallook[ega->egapal[(dat >> 4)  & ega->attrregs[0x12]]];
430                 dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2);
431                 ((uint32_t *)buffer32->line[ega->displine])[(x << 4) +  2 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) +  3 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]];
432                 ((uint32_t *)buffer32->line[ega->displine])[(x << 4) +      offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) +  1 + offset] = ega->pallook[ega->egapal[(dat >> 4)  & ega->attrregs[0x12]]];
433         }
434 }
435 
ega_draw_4bpp_highres(ega_t * ega)436 static void ega_draw_4bpp_highres(ega_t *ega)
437 {
438         int x;
439         int offset = (8 - ega->scrollcache) + 24;
440 
441         for (x = 0; x <= ega->hdisp; x++)
442         {
443                 uint8_t edat[4];
444                 uint8_t dat;
445                 uint32_t addr = ega->ma;
446                 int oddeven = 0;
447 
448                 if (!(ega->crtc[0x17] & 0x40))
449                 {
450                         addr = (addr << 1) & ega->vrammask;
451                         if (ega->seqregs[1] & 4)
452                                 oddeven = (addr & 4) ? 1 : 0;
453                         addr &= ~7;
454                         if ((ega->crtc[0x17] & 0x20) && (ega->ma & 0x20000))
455                                 addr |= 4;
456                         if (!(ega->crtc[0x17] & 0x20) && (ega->ma & 0x8000))
457                                 addr |= 4;
458                 }
459                 if (!(ega->crtc[0x17] & 0x01))
460                         addr = (addr & ~0x8000) | ((ega->sc & 1) ? 0x8000 : 0);
461                 if (!(ega->crtc[0x17] & 0x02))
462                         addr = (addr & ~0x10000) | ((ega->sc & 2) ? 0x10000 : 0);
463 
464                 if (ega->seqregs[1] & 4)
465                 {
466                         edat[0] = ega->vram[addr | oddeven];
467                         edat[2] = ega->vram[addr | oddeven | 0x2];
468                         edat[1] = edat[3] = 0;
469                         ega->ma += 2;
470                 }
471                 else
472                 {
473                         edat[0] = ega->vram[addr];
474                         edat[1] = ega->vram[addr | 0x1];
475                         edat[2] = ega->vram[addr | 0x2];
476                         edat[3] = ega->vram[addr | 0x3];
477                         ega->ma += 4;
478                 }
479                 ega->ma &= ega->vrammask;
480 
481                 dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2);
482                 ((uint32_t *)buffer32->line[ega->displine])[(x << 3) + 7 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]];
483                 ((uint32_t *)buffer32->line[ega->displine])[(x << 3) + 6 + offset] = ega->pallook[ega->egapal[(dat >> 4)  & ega->attrregs[0x12]]];
484                 dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2);
485                 ((uint32_t *)buffer32->line[ega->displine])[(x << 3) + 5 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]];
486                 ((uint32_t *)buffer32->line[ega->displine])[(x << 3) + 4 + offset] = ega->pallook[ega->egapal[(dat >> 4)  & ega->attrregs[0x12]]];
487                 dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2);
488                 ((uint32_t *)buffer32->line[ega->displine])[(x << 3) + 3 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]];
489                 ((uint32_t *)buffer32->line[ega->displine])[(x << 3) + 2 + offset] = ega->pallook[ega->egapal[(dat >> 4)  & ega->attrregs[0x12]]];
490                 dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2);
491                 ((uint32_t *)buffer32->line[ega->displine])[(x << 3) + 1 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]];
492                 ((uint32_t *)buffer32->line[ega->displine])[(x << 3) +     offset] = ega->pallook[ega->egapal[(dat >> 4)  & ega->attrregs[0x12]]];
493         }
494 }
495 
ega_poll(void * p)496 void ega_poll(void *p)
497 {
498         ega_t *ega = (ega_t *)p;
499         int x, xx;
500 
501         if (!ega->linepos)
502         {
503                 ega->vidtime += ega->dispofftime;
504 
505                 ega->stat |= 1;
506                 ega->linepos = 1;
507 
508                 if (ega->dispon)
509                 {
510                         if (ega->firstline == 2000)
511                         {
512                                 ega->firstline = ega->displine;
513                                 video_wait_for_buffer();
514                         }
515 
516                         if (ega->scrblank)
517                         {
518                                 for (x = 0; x < ega->hdisp; x++)
519                                 {
520                                         switch (ega->seqregs[1] & 9)
521                                         {
522                                                 case 0:
523                                                 for (xx = 0; xx < 9; xx++)  ((uint32_t *)buffer32->line[ega->displine])[(x * 9) + xx + 32] = 0;
524                                                 break;
525                                                 case 1:
526                                                 for (xx = 0; xx < 8; xx++)  ((uint32_t *)buffer32->line[ega->displine])[(x * 8) + xx + 32] = 0;
527                                                 break;
528                                                 case 8:
529                                                 for (xx = 0; xx < 18; xx++) ((uint32_t *)buffer32->line[ega->displine])[(x * 18) + xx + 32] = 0;
530                                                 break;
531                                                 case 9:
532                                                 for (xx = 0; xx < 16; xx++) ((uint32_t *)buffer32->line[ega->displine])[(x * 16) + xx + 32] = 0;
533                                                 break;
534                                         }
535                                 }
536                         }
537                         else if (!(ega->gdcreg[6] & 1))
538                         {
539                                 if (fullchange)
540                                         ega_draw_text(ega);
541                         }
542                         else
543                         {
544                                 switch (ega->gdcreg[5] & 0x20)
545                                 {
546                                         case 0x00:
547                                         if (ega->seqregs[1] & 8)
548                                                 ega_draw_4bpp_lowres(ega);
549                                         else
550                                                 ega_draw_4bpp_highres(ega);
551                                         break;
552                                         case 0x20:
553                                         ega_draw_2bpp(ega);
554                                         break;
555                                 }
556                         }
557                         if (ega->lastline < ega->displine)
558                                 ega->lastline = ega->displine;
559                 }
560 
561                 ega->displine++;
562                 if ((ega->stat & 8) && ((ega->displine & 15) == (ega->crtc[0x11] & 15)) && ega->vslines)
563                         ega->stat &= ~8;
564                 ega->vslines++;
565                 if (ega->displine > 500)
566                         ega->displine = 0;
567         }
568         else
569         {
570                 ega->vidtime += ega->dispontime;
571 //                if (output) printf("Display on %f\n",vidtime);
572                 if (ega->dispon)
573                         ega->stat &= ~1;
574                 ega->linepos = 0;
575                 if (ega->sc == (ega->crtc[11] & 31))
576                    ega->con = 0;
577                 if (ega->dispon)
578                 {
579                         if (ega->sc == (ega->crtc[9] & 31))
580                         {
581                                 ega->sc = 0;
582                                 if (ega->sc == (ega->crtc[11] & 31))
583                                         ega->con = 0;
584 
585                                 ega->maback += (ega->rowoffset << 3);
586                                 ega->maback &= ega->vrammask;
587                                 ega->ma = ega->maback;
588                         }
589                         else
590                         {
591                                 ega->sc++;
592                                 ega->sc &= 31;
593                                 ega->ma = ega->maback;
594                         }
595                 }
596                 ega->vc++;
597                 ega->vc &= 1023;
598 //                printf("Line now %i %i ma %05X\n",vc,displine,ma);
599                 if (ega->vc == ega->split)
600                 {
601 //                        printf("Split at line %i %i\n",displine,vc);
602                         ega->ma = ega->maback = 0;
603                         if (ega->attrregs[0x10] & 0x20)
604                                 ega->scrollcache = 0;
605                 }
606                 if (ega->vc == ega->dispend)
607                 {
608 //                        printf("Display over at line %i %i\n",displine,vc);
609                         ega->dispon=0;
610                         if (ega->crtc[10] & 0x20) ega->cursoron = 0;
611                         else                      ega->cursoron = ega->blink & 16;
612                         if (!(ega->gdcreg[6] & 1) && !(ega->blink & 15))
613                                 fullchange = 2;
614                         ega->blink++;
615 
616                         if (fullchange)
617                                 fullchange--;
618                 }
619                 if (ega->vc == ega->vsyncstart)
620                 {
621                         ega->dispon = 0;
622 //                        printf("Vsync on at line %i %i\n",displine,vc);
623                         ega->stat |= 8;
624                         if (ega->seqregs[1] & 8) x = ega->hdisp * ((ega->seqregs[1] & 1) ? 8 : 9) * 2;
625                         else                     x = ega->hdisp * ((ega->seqregs[1] & 1) ? 8 : 9);
626 //                        pclog("Cursor %02X %02X\n",crtc[10],crtc[11]);
627 //                        pclog("Firstline %i Lastline %i wx %i %i\n",firstline,lastline,wx,oddeven);
628 //                        doblit();
629                         if (x != xsize || (ega->lastline - ega->firstline) != ysize)
630                         {
631                                 xsize = x;
632                                 ysize = ega->lastline - ega->firstline;
633                                 if (xsize < 64) xsize = 656;
634                                 if (ysize < 32) ysize = 200;
635                                 if (ega->vres || ysize <= 200)
636                                         updatewindowsize(xsize, ysize << 1);
637                                 else
638                                         updatewindowsize(xsize, ysize);
639                         }
640 
641                         video_blit_memtoscreen(32, 0, ega->firstline, ega->lastline, xsize, ega->lastline - ega->firstline);
642 
643                         ega->frames++;
644                         ega->video_res_x = xsize;
645                         ega->video_res_y = ysize+1;
646                         if (!(ega->gdcreg[6] & 1)) /*Text mode*/
647                         {
648                                 ega->video_res_x /= (ega->seqregs[1] & 1) ? 8 : 9;
649                                 ega->video_res_y /= (ega->crtc[9] & 31) + 1;
650                                 ega->video_bpp = 0;
651                         }
652                         else
653                         {
654                                 if (ega->crtc[9] & 0x80)
655                                    ega->video_res_y /= 2;
656                                 if (!(ega->crtc[0x17] & 1))
657                                    ega->video_res_y *= 2;
658                                 ega->video_res_y /= (ega->crtc[9] & 31) + 1;
659                                 if (ega->seqregs[1] & 8)
660                                    ega->video_res_x /= 2;
661                                 ega->video_bpp = (ega->gdcreg[5] & 0x20) ? 2 : 4;
662                         }
663 
664 //                        wakeupblit();
665                         readflash=0;
666                         //framecount++;
667                         ega->firstline = 2000;
668                         ega->lastline = 0;
669 
670                         ega->maback = ega->ma = (ega->crtc[0xc] << 8)| ega->crtc[0xd];
671                         ega->ca = (ega->crtc[0xe] << 8) | ega->crtc[0xf];
672                         ega->ma <<= 2;
673                         ega->maback <<= 2;
674                         ega->ca <<= 2;
675                         changeframecount = 2;
676                         ega->vslines = 0;
677                 }
678                 if (ega->vc == ega->vtotal)
679                 {
680                         ega->vc = 0;
681                         ega->sc = ega->crtc[8] & 0x1f;
682                         ega->dispon = 1;
683                         ega->displine = 0;
684                         ega->scrollcache = ega->attrregs[0x13] & 7;
685                 }
686                 if (ega->sc == (ega->crtc[10] & 31))
687                         ega->con = 1;
688         }
689 }
690 
691 
ega_write(uint32_t addr,uint8_t val,void * p)692 void ega_write(uint32_t addr, uint8_t val, void *p)
693 {
694         ega_t *ega = (ega_t *)p;
695         uint8_t vala, valb, valc, vald;
696         int writemask2 = ega->writemask;
697 
698         egawrites++;
699         cycles -= video_timing_write_b;
700         cycles_lost += video_timing_write_b;
701 
702         if (addr >= 0xB0000) addr &= 0x7fff;
703         else                 addr &= 0xffff;
704 
705         if (ega->chain2_write)
706         {
707                 writemask2 &= ~0xa;
708                 if (addr & 1)
709                         writemask2 <<= 1;
710                 addr &= ~1;
711                 if (addr & 0x4000)
712                         addr |= 1;
713                 addr &= ~0x4000;
714         }
715 
716         addr <<= 2;
717 
718         if (addr >= ega->vram_limit)
719                 return;
720 
721         if (!(ega->gdcreg[6] & 1))
722                 fullchange = 2;
723 
724 //        pclog("%i %08X %i %i %02X   %02X %02X %02X %02X\n",chain4,addr,writemode,writemask,gdcreg[8],vram[0],vram[1],vram[2],vram[3]);
725         switch (ega->writemode)
726         {
727                 case 1:
728                 if (writemask2 & 1) ega->vram[addr]       = ega->la;
729                 if (writemask2 & 2) ega->vram[addr | 0x1] = ega->lb;
730                 if (writemask2 & 4) ega->vram[addr | 0x2] = ega->lc;
731                 if (writemask2 & 8) ega->vram[addr | 0x3] = ega->ld;
732                 break;
733                 case 0:
734                 if (ega->gdcreg[3] & 7)
735                         val = ega_rotate[ega->gdcreg[3] & 7][val];
736 
737                 if (ega->gdcreg[8] == 0xff && !(ega->gdcreg[3] & 0x18) && !ega->gdcreg[1])
738                 {
739                         if (writemask2 & 1) ega->vram[addr]       = val;
740                         if (writemask2 & 2) ega->vram[addr | 0x1] = val;
741                         if (writemask2 & 4) ega->vram[addr | 0x2] = val;
742                         if (writemask2 & 8) ega->vram[addr | 0x3] = val;
743                 }
744                 else
745                 {
746                         if (ega->gdcreg[1] & 1) vala = (ega->gdcreg[0] & 1) ? 0xff : 0;
747                         else                    vala = val;
748                         if (ega->gdcreg[1] & 2) valb = (ega->gdcreg[0] & 2) ? 0xff : 0;
749                         else                    valb = val;
750                         if (ega->gdcreg[1] & 4) valc = (ega->gdcreg[0] & 4) ? 0xff : 0;
751                         else                    valc = val;
752                         if (ega->gdcreg[1] & 8) vald = (ega->gdcreg[0] & 8) ? 0xff : 0;
753                         else                    vald = val;
754 //                                pclog("Write %02X %01X %02X %02X %02X %02X  %02X\n",gdcreg[3]&0x18,writemask,vala,valb,valc,vald,gdcreg[8]);
755                         switch (ega->gdcreg[3] & 0x18)
756                         {
757                                 case 0: /*Set*/
758                                 if (writemask2 & 1) ega->vram[addr]       = (vala & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]);
759                                 if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]);
760                                 if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]);
761                                 if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]);
762                                 break;
763                                 case 8: /*AND*/
764                                 if (writemask2 & 1) ega->vram[addr]       = (vala | ~ega->gdcreg[8]) & ega->la;
765                                 if (writemask2 & 2) ega->vram[addr | 0x1] = (valb | ~ega->gdcreg[8]) & ega->lb;
766                                 if (writemask2 & 4) ega->vram[addr | 0x2] = (valc | ~ega->gdcreg[8]) & ega->lc;
767                                 if (writemask2 & 8) ega->vram[addr | 0x3] = (vald | ~ega->gdcreg[8]) & ega->ld;
768                                 break;
769                                 case 0x10: /*OR*/
770                                 if (writemask2 & 1) ega->vram[addr]       = (vala & ega->gdcreg[8]) | ega->la;
771                                 if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | ega->lb;
772                                 if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | ega->lc;
773                                 if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | ega->ld;
774                                 break;
775                                 case 0x18: /*XOR*/
776                                 if (writemask2 & 1) ega->vram[addr]       = (vala & ega->gdcreg[8]) ^ ega->la;
777                                 if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) ^ ega->lb;
778                                 if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) ^ ega->lc;
779                                 if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) ^ ega->ld;
780                                 break;
781                         }
782 //                                pclog("- %02X %02X %02X %02X   %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr);
783                 }
784                 break;
785                 case 2:
786                 if (!(ega->gdcreg[3] & 0x18) && !ega->gdcreg[1])
787                 {
788                         if (writemask2 & 1) ega->vram[addr]       = (((val & 1) ? 0xff : 0) & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]);
789                         if (writemask2 & 2) ega->vram[addr | 0x1] = (((val & 2) ? 0xff : 0) & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]);
790                         if (writemask2 & 4) ega->vram[addr | 0x2] = (((val & 4) ? 0xff : 0) & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]);
791                         if (writemask2 & 8) ega->vram[addr | 0x3] = (((val & 8) ? 0xff : 0) & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]);
792                 }
793                 else
794                 {
795                         vala = ((val & 1) ? 0xff : 0);
796                         valb = ((val & 2) ? 0xff : 0);
797                         valc = ((val & 4) ? 0xff : 0);
798                         vald = ((val & 8) ? 0xff : 0);
799                         switch (ega->gdcreg[3] & 0x18)
800                         {
801                                 case 0: /*Set*/
802                                 if (writemask2 & 1) ega->vram[addr]       = (vala & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]);
803                                 if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]);
804                                 if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]);
805                                 if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]);
806                                 break;
807                                 case 8: /*AND*/
808                                 if (writemask2 & 1) ega->vram[addr]       = (vala | ~ega->gdcreg[8]) & ega->la;
809                                 if (writemask2 & 2) ega->vram[addr | 0x1] = (valb | ~ega->gdcreg[8]) & ega->lb;
810                                 if (writemask2 & 4) ega->vram[addr | 0x2] = (valc | ~ega->gdcreg[8]) & ega->lc;
811                                 if (writemask2 & 8) ega->vram[addr | 0x3] = (vald | ~ega->gdcreg[8]) & ega->ld;
812                                 break;
813                                 case 0x10: /*OR*/
814                                 if (writemask2 & 1) ega->vram[addr]       = (vala & ega->gdcreg[8]) | ega->la;
815                                 if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | ega->lb;
816                                 if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | ega->lc;
817                                 if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | ega->ld;
818                                 break;
819                                 case 0x18: /*XOR*/
820                                 if (writemask2 & 1) ega->vram[addr]       = (vala & ega->gdcreg[8]) ^ ega->la;
821                                 if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) ^ ega->lb;
822                                 if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) ^ ega->lc;
823                                 if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) ^ ega->ld;
824                                 break;
825                         }
826                 }
827                 break;
828         }
829 }
830 
ega_read(uint32_t addr,void * p)831 uint8_t ega_read(uint32_t addr, void *p)
832 {
833         ega_t *ega = (ega_t *)p;
834         uint8_t temp, temp2, temp3, temp4;
835         int readplane = ega->readplane;
836 
837         egareads++;
838         cycles -= video_timing_read_b;
839         cycles_lost += video_timing_read_b;
840 //        pclog("Readega %06X   ",addr);
841         if (addr >= 0xb0000) addr &= 0x7fff;
842         else                 addr &= 0xffff;
843 
844         if (ega->chain2_read)
845         {
846                 readplane = (readplane & 2) | (addr & 1);
847                 addr &= ~1;
848                 if (addr & 0x4000)
849                         addr |= 1;
850                 addr &= ~0x4000;
851         }
852 
853         addr <<= 2;
854         if (addr >= ega->vram_limit)
855                 return 0xff;
856 
857         ega->la = ega->vram[addr];
858         ega->lb = ega->vram[addr | 0x1];
859         ega->lc = ega->vram[addr | 0x2];
860         ega->ld = ega->vram[addr | 0x3];
861         if (ega->readmode)
862         {
863                 temp   = ega->la;
864                 temp  ^= (ega->colourcompare & 1) ? 0xff : 0;
865                 temp  &= (ega->colournocare & 1)  ? 0xff : 0;
866                 temp2  = ega->lb;
867                 temp2 ^= (ega->colourcompare & 2) ? 0xff : 0;
868                 temp2 &= (ega->colournocare & 2)  ? 0xff : 0;
869                 temp3  = ega->lc;
870                 temp3 ^= (ega->colourcompare & 4) ? 0xff : 0;
871                 temp3 &= (ega->colournocare & 4)  ? 0xff : 0;
872                 temp4  = ega->ld;
873                 temp4 ^= (ega->colourcompare & 8) ? 0xff : 0;
874                 temp4 &= (ega->colournocare & 8)  ? 0xff : 0;
875                 return ~(temp | temp2 | temp3 | temp4);
876         }
877         return ega->vram[addr | readplane];
878 }
879 
ega_init(ega_t * ega,int monitor_type,int is_mono)880 void ega_init(ega_t *ega, int monitor_type, int is_mono)
881 {
882         int c, d, e;
883 
884         ega->vram = malloc(0x40000);
885         ega->vrammask = 0x3ffff;
886 
887         for (c = 0; c < 256; c++)
888         {
889                 e = c;
890                 for (d = 0; d < 8; d++)
891                 {
892                         ega_rotate[d][c] = e;
893                         e = (e >> 1) | ((e & 1) ? 0x80 : 0);
894                 }
895         }
896 
897         for (c = 0; c < 4; c++)
898         {
899                 for (d = 0; d < 4; d++)
900                 {
901                         edatlookup[c][d] = 0;
902                         if (c & 1) edatlookup[c][d] |= 1;
903                         if (d & 1) edatlookup[c][d] |= 2;
904                         if (c & 2) edatlookup[c][d] |= 0x10;
905                         if (d & 2) edatlookup[c][d] |= 0x20;
906                 }
907         }
908 
909         if (is_mono)
910         {
911                 for (c = 0; c < 256; c++)
912                 {
913                         switch (monitor_type >> 4)
914                         {
915                                 case DISPLAY_GREEN:
916                                 switch ((c >> 3) & 3)
917                                 {
918                                         case 0:
919                                         pallook64[c] = pallook16[c] = makecol32(0, 0, 0);
920                                         break;
921                                         case 2:
922                                         pallook64[c] = pallook16[c] = makecol32(0x04, 0x8a, 0x20);
923                                         break;
924                                         case 1:
925                                         pallook64[c] = pallook16[c] = makecol32(0x08, 0xc7, 0x2c);
926                                         break;
927                                         case 3:
928                                         pallook64[c] = pallook16[c] = makecol32(0x34, 0xff, 0x5d);
929                                         break;
930                                 }
931                                 break;
932                                 case DISPLAY_AMBER:
933                                 switch ((c >> 3) & 3)
934                                 {
935                                         case 0:
936                                         pallook64[c] = pallook16[c] = makecol32(0, 0, 0);
937                                         break;
938                                         case 2:
939                                         pallook64[c] = pallook16[c] = makecol32(0xb2, 0x4d, 0x00);
940                                         break;
941                                         case 1:
942                                         pallook64[c] = pallook16[c] = makecol32(0xef, 0x79, 0x00);
943                                         break;
944                                         case 3:
945                                         pallook64[c] = pallook16[c] = makecol32(0xff, 0xe3, 0x34);
946                                         break;
947                                 }
948                                 break;
949                                 case DISPLAY_WHITE: default:
950                                 switch ((c >> 3) & 3)
951                                 {
952                                         case 0:
953                                         pallook64[c] = pallook16[c] = makecol32(0, 0, 0);
954                                         break;
955                                         case 2:
956                                         pallook64[c] = pallook16[c] = makecol32(0x7a, 0x81, 0x83);
957                                         break;
958                                         case 1:
959                                         pallook64[c] = pallook16[c] = makecol32(0xaf, 0xb3, 0xb0);
960                                         break;
961                                         case 3:
962                                         pallook64[c] = pallook16[c] = makecol32(0xff, 0xfd, 0xed);
963                                         break;
964                                 }
965                                 break;
966                         }
967                 }
968         }
969         else
970         {
971                 for (c = 0; c < 256; c++)
972                 {
973                         pallook64[c]  = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa);
974                         pallook64[c] += makecol32(((c >> 5) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 3) & 1) * 0x55);
975                         pallook16[c]  = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa);
976                         pallook16[c] += makecol32(((c >> 4) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 4) & 1) * 0x55);
977                         if ((c & 0x17) == 6)
978                                 pallook16[c] = makecol32(0xaa, 0x55, 0);
979                 }
980         }
981         ega->pallook = pallook16;
982 
983         egaswitches = monitor_type & 0xf;
984         ega->vram_limit = 256 * 1024;
985         ega->vrammask = ega->vram_limit-1;
986 }
987 
ega_standalone_init()988 void *ega_standalone_init()
989 {
990         ega_t *ega = malloc(sizeof(ega_t));
991         memset(ega, 0, sizeof(ega_t));
992         int monitor_type;
993 
994         rom_init(&ega->bios_rom, "ibm_6277356_ega_card_u44_27128.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
995 
996         if (ega->bios_rom.rom[0x3ffe] == 0xaa && ega->bios_rom.rom[0x3fff] == 0x55)
997         {
998                 int c;
999                 pclog("Read EGA ROM in reverse\n");
1000 
1001                 for (c = 0; c < 0x2000; c++)
1002                 {
1003                         uint8_t temp = ega->bios_rom.rom[c];
1004                         ega->bios_rom.rom[c] = ega->bios_rom.rom[0x3fff - c];
1005                         ega->bios_rom.rom[0x3fff - c] = temp;
1006                 }
1007         }
1008 
1009         monitor_type = device_get_config_int("monitor_type");
1010         ega_init(ega, monitor_type, (monitor_type & 0xf) == 10);
1011 
1012         ega->vram_limit = device_get_config_int("memory") * 1024;
1013         ega->vrammask = ega->vram_limit-1;
1014 
1015         mem_mapping_add(&ega->mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, ega);
1016         timer_add(ega_poll, &ega->vidtime, TIMER_ALWAYS_ENABLED, ega);
1017         io_sethandler(0x03a0, 0x0040, ega_in, NULL, NULL, ega_out, NULL, NULL, ega);
1018         return ega;
1019 }
1020 
ega_standalone_available()1021 static int ega_standalone_available()
1022 {
1023         return rom_present("ibm_6277356_ega_card_u44_27128.bin");
1024 }
1025 
ega_close(void * p)1026 void ega_close(void *p)
1027 {
1028         ega_t *ega = (ega_t *)p;
1029 
1030         free(ega->vram);
1031         free(ega);
1032 }
1033 
ega_speed_changed(void * p)1034 void ega_speed_changed(void *p)
1035 {
1036         ega_t *ega = (ega_t *)p;
1037 
1038         ega_recalctimings(ega);
1039 }
1040 
ega_add_status_info(char * s,int max_len,void * p)1041 void ega_add_status_info(char *s, int max_len, void *p)
1042 {
1043         ega_t *ega = (ega_t *)p;
1044         char temps[128];
1045 
1046         if (!ega->video_bpp)      strcpy(temps, "EGA in text mode\n");
1047         else                      sprintf(temps, "EGA colour depth : %i bpp\n", ega->video_bpp);
1048         strncat(s, temps, max_len);
1049 
1050         sprintf(temps, "EGA resolution : %i x %i\n", ega->video_res_x, ega->video_res_y);
1051         strncat(s, temps, max_len);
1052 
1053         sprintf(temps, "EGA refresh rate : %i Hz\n\n", ega->frames);
1054         ega->frames = 0;
1055         strncat(s, temps, max_len);
1056 }
1057 
1058 static device_config_t ega_config[] =
1059 {
1060         {
1061                 .name = "memory",
1062                 .description = "Memory size",
1063                 .type = CONFIG_SELECTION,
1064                 .selection =
1065                 {
1066                         {
1067                                 .description = "64 kB",
1068                                 .value = 64
1069                         },
1070                         {
1071                                 .description = "128 kB",
1072                                 .value = 128
1073                         },
1074                         {
1075                                 .description = "256 kB",
1076                                 .value = 256
1077                         },
1078                         {
1079                                 .description = ""
1080                         }
1081                 },
1082                 .default_int = 256
1083         },
1084         {
1085                 .name = "monitor_type",
1086                 .description = "Monitor type",
1087                 .type = CONFIG_SELECTION,
1088                 .selection =
1089                 {
1090                         {
1091                                 .description = "EGA Colour, 40x25",
1092                                 .value = 6
1093                         },
1094                         {
1095                                 .description = "EGA Colour, 80x25",
1096                                 .value = 7
1097                         },
1098                         {
1099                                 .description = "EGA Colour, ECD",
1100                                 .value = 9
1101                         },
1102                         {
1103                                 .description = "EGA Monochrome (white)",
1104                                 .value = 10 | (DISPLAY_WHITE << 4)
1105                         },
1106                         {
1107                                 .description = "EGA Monochrome (green)",
1108                                 .value = 10 | (DISPLAY_GREEN << 4)
1109                         },
1110                         {
1111                                 .description = "EGA Monochrome (amber)",
1112                                 .value = 10 | (DISPLAY_AMBER << 4)
1113                         },
1114                         {
1115                                 .description = ""
1116                         }
1117                 },
1118                 .default_int = 9
1119         },
1120         {
1121                 .type = -1
1122         }
1123 };
1124 
1125 device_t ega_device =
1126 {
1127         "EGA",
1128         0,
1129         ega_standalone_init,
1130         ega_close,
1131         ega_standalone_available,
1132         ega_speed_changed,
1133         NULL,
1134         ega_add_status_info,
1135         ega_config
1136 };
1137