PCem
view src/vid_ega.c @ 131:f22b6152c221
Fixed memory mapping on ISA video cards - should now work on Award 430VX PCI.
| author | TomW |
|---|---|
| date | Wed Jul 16 20:00:34 2014 +0100 |
| parents | b53e148867e5 |
| children |
line source
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"
12 extern uint8_t edatlookup[4][4];
14 static uint8_t ega_rotate[8][256];
16 static uint32_t pallook16[256], pallook64[256];
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)*/
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;
27 if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1))
28 addr ^= 0x60;
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 }
81 break;
82 case 0x3ce:
83 ega->gdcaddr = val;
84 break;
85 case 0x3cf:
86 ega->gdcreg[ega->gdcaddr & 15] = val;
87 switch (ega->gdcaddr & 15)
88 {
89 case 2:
90 ega->colourcompare = val;
91 break;
92 case 4:
93 ega->readplane = val & 3;
94 break;
95 case 5:
96 ega->writemode = val & 3;
97 ega->readmode = val & 8;
98 break;
99 case 6:
100 // pclog("Write mapping %02X\n", val);
101 switch (val & 0xc)
102 {
103 case 0x0: /*128k at A0000*/
104 mem_mapping_set_addr(&ega->mapping, 0xa0000, 0x20000);
105 break;
106 case 0x4: /*64k at A0000*/
107 mem_mapping_set_addr(&ega->mapping, 0xa0000, 0x10000);
108 break;
109 case 0x8: /*32k at B0000*/
110 mem_mapping_set_addr(&ega->mapping, 0xb0000, 0x08000);
111 break;
112 case 0xC: /*32k at B8000*/
113 mem_mapping_set_addr(&ega->mapping, 0xb8000, 0x08000);
114 break;
115 }
116 break;
117 case 7:
118 ega->colournocare = val;
119 break;
120 }
121 break;
122 case 0x3d4:
123 pclog("Write 3d4 %02X %04X:%04X\n", val, CS, pc);
124 ega->crtcreg = val & 31;
125 return;
126 case 0x3d5:
127 pclog("Write 3d5 %02X %02X %02X\n", ega->crtcreg, val, ega->crtc[0x11]);
128 // if (ega->crtcreg == 1 && val == 0x14)
129 // fatal("Here\n");
130 if (ega->crtcreg <= 7 && ega->crtc[0x11] & 0x80) return;
131 old = ega->crtc[ega->crtcreg];
132 ega->crtc[ega->crtcreg] = val;
133 if (old != val)
134 {
135 if (ega->crtcreg < 0xe || ega->crtcreg > 0x10)
136 {
137 fullchange = changeframecount;
138 ega_recalctimings(ega);
139 }
140 }
141 break;
142 }
143 }
145 uint8_t ega_in(uint16_t addr, void *p)
146 {
147 ega_t *ega = (ega_t *)p;
149 if (addr != 0x3da && addr != 0x3ba)
150 pclog("ega_in %04X\n", addr);
151 if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1))
152 addr ^= 0x60;
154 switch (addr)
155 {
156 case 0x3c0:
157 return ega->attraddr;
158 case 0x3c1:
159 return ega->attrregs[ega->attraddr];
160 case 0x3c2:
161 // printf("Read egaswitch %02X %02X %i\n",egaswitchread,egaswitches,VGA);
162 switch (egaswitchread)
163 {
164 case 0xc: return (egaswitches & 1) ? 0x10 : 0;
165 case 0x8: return (egaswitches & 2) ? 0x10 : 0;
166 case 0x4: return (egaswitches & 4) ? 0x10 : 0;
167 case 0x0: return (egaswitches & 8) ? 0x10 : 0;
168 }
169 break;
170 case 0x3c4:
171 return ega->seqaddr;
172 case 0x3c5:
173 return ega->seqregs[ega->seqaddr & 0xf];
174 case 0x3ce:
175 return ega->gdcaddr;
176 case 0x3cf:
177 return ega->gdcreg[ega->gdcaddr & 0xf];
178 case 0x3d4:
179 return ega->crtcreg;
180 case 0x3d5:
181 return ega->crtc[ega->crtcreg];
182 case 0x3da:
183 ega->attrff = 0;
184 ega->stat ^= 0x30; /*Fools IBM EGA video BIOS self-test*/
185 return ega->stat;
186 }
187 // printf("Bad EGA read %04X %04X:%04X\n",addr,cs>>4,pc);
188 return 0xff;
189 }
191 void ega_recalctimings(ega_t *ega)
192 {
193 double _dispontime, _dispofftime, disptime;
194 double crtcconst;
196 ega->vtotal = ega->crtc[6];
197 ega->dispend = ega->crtc[0x12];
198 ega->vsyncstart = ega->crtc[0x10];
199 ega->split = ega->crtc[0x18];
201 if (ega->crtc[7] & 1) ega->vtotal |= 0x100;
202 if (ega->crtc[7] & 32) ega->vtotal |= 0x200;
203 ega->vtotal++;
205 if (ega->crtc[7] & 2) ega->dispend |= 0x100;
206 if (ega->crtc[7] & 64) ega->dispend |= 0x200;
207 ega->dispend++;
209 if (ega->crtc[7] & 4) ega->vsyncstart |= 0x100;
210 if (ega->crtc[7] & 128) ega->vsyncstart |= 0x200;
211 ega->vsyncstart++;
213 if (ega->crtc[7] & 0x10) ega->split |= 0x100;
214 if (ega->crtc[9] & 0x40) ega->split |= 0x200;
215 ega->split+=2;
217 ega->hdisp = ega->crtc[1];
218 ega->hdisp++;
220 ega->rowoffset = ega->crtc[0x13];
222 printf("Recalc! %i %i %i %i %i %02X\n", ega->vtotal, ega->dispend, ega->vsyncstart, ega->split, ega->hdisp, ega->attrregs[0x16]);
224 if (ega->vidclock) crtcconst = (ega->seqregs[1] & 1) ? MDACONST : (MDACONST * (9.0 / 8.0));
225 else crtcconst = (ega->seqregs[1] & 1) ? CGACONST : (CGACONST * (9.0 / 8.0));
227 disptime = ega->crtc[0] + 2;
228 _dispontime = ega->crtc[1] + 1;
230 printf("Disptime %f dispontime %f hdisp %i\n", disptime, _dispontime, ega->crtc[1] * 8);
231 if (ega->seqregs[1] & 8)
232 {
233 disptime*=2;
234 _dispontime*=2;
235 }
236 _dispofftime = disptime - _dispontime;
237 _dispontime *= crtcconst;
238 _dispofftime *= crtcconst;
240 ega->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT));
241 ega->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT));
242 pclog("dispontime %i (%f) dispofftime %i (%f)\n", ega->dispontime, (float)ega->dispontime / (1 << TIMER_SHIFT),
243 ega->dispofftime, (float)ega->dispofftime / (1 << TIMER_SHIFT));
244 // 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));
245 // printf("EGA vert total %i display end %i max row %i vsync %i\n",ega_vtotal,ega_dispend,(crtc[9]&31)+1,ega_vsyncstart);
246 // 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]);
247 }
249 void ega_poll(void *p)
250 {
251 ega_t *ega = (ega_t *)p;
252 uint8_t chr, dat, attr;
253 uint32_t charaddr;
254 int x, xx;
255 uint32_t fg, bg;
256 int offset;
257 uint8_t edat[4];
258 int drawcursor = 0;
260 if (!ega->linepos)
261 {
262 ega->vidtime += ega->dispofftime;
264 ega->stat |= 1;
265 ega->linepos = 1;
267 if (ega->dispon)
268 {
269 if (ega->firstline == 2000)
270 ega->firstline = ega->displine;
272 if (ega->scrblank)
273 {
274 for (x = 0; x < ega->hdisp; x++)
275 {
276 switch (ega->seqregs[1] & 9)
277 {
278 case 0:
279 for (xx = 0; xx < 9; xx++) ((uint32_t *)buffer32->line[ega->displine])[(x * 9) + xx + 32] = 0;
280 break;
281 case 1:
282 for (xx = 0; xx < 8; xx++) ((uint32_t *)buffer32->line[ega->displine])[(x * 8) + xx + 32] = 0;
283 break;
284 case 8:
285 for (xx = 0; xx < 18; xx++) ((uint32_t *)buffer32->line[ega->displine])[(x * 18) + xx + 32] = 0;
286 break;
287 case 9:
288 for (xx = 0; xx < 16; xx++) ((uint32_t *)buffer32->line[ega->displine])[(x * 16) + xx + 32] = 0;
289 break;
290 }
291 }
292 }
293 else if (!(ega->gdcreg[6] & 1))
294 {
295 if (fullchange)
296 {
297 for (x = 0; x < ega->hdisp; x++)
298 {
299 drawcursor = ((ega->ma == ega->ca) && ega->con && ega->cursoron);
300 chr = ega->vram[(ega->ma << 1) & ega->vrammask];
301 attr = ega->vram[((ega->ma << 1) + 4) & ega->vrammask];
303 if (attr & 8) charaddr = ega->charsetb + (chr * 128);
304 else charaddr = ega->charseta + (chr * 128);
306 if (drawcursor)
307 {
308 bg = ega->pallook[ega->egapal[attr & 15]];
309 fg = ega->pallook[ega->egapal[attr >> 4]];
310 }
311 else
312 {
313 fg = ega->pallook[ega->egapal[attr & 15]];
314 bg = ega->pallook[ega->egapal[attr >> 4]];
315 if (attr & 0x80 && ega->attrregs[0x10] & 8)
316 {
317 bg = ega->pallook[ega->egapal[(attr >> 4) & 7]];
318 if (ega->blink & 16)
319 fg = bg;
320 }
321 }
323 dat = ega->vram[charaddr + (ega->sc << 2)];
324 if (ega->seqregs[1] & 8)
325 {
326 if (ega->seqregs[1] & 1)
327 {
328 for (xx = 0; xx < 8; xx++)
329 ((uint32_t *)buffer32->line[ega->displine])[((x << 4) + 32 + (xx << 1)) & 2047] =
330 ((uint32_t *)buffer32->line[ega->displine])[((x << 4) + 33 + (xx << 1)) & 2047] = (dat & (0x80 >> xx)) ? fg : bg;
331 }
332 else
333 {
334 for (xx = 0; xx < 8; xx++)
335 ((uint32_t *)buffer32->line[ega->displine])[((x * 18) + 32 + (xx << 1)) & 2047] =
336 ((uint32_t *)buffer32->line[ega->displine])[((x * 18) + 33 + (xx << 1)) & 2047] = (dat & (0x80 >> xx)) ? fg : bg;
337 if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4))
338 ((uint32_t *)buffer32->line[ega->displine])[((x * 18) + 32 + 16) & 2047] =
339 ((uint32_t *)buffer32->line[ega->displine])[((x * 18) + 32 + 17) & 2047] = bg;
340 else
341 ((uint32_t *)buffer32->line[ega->displine])[((x * 18) + 32 + 16) & 2047] =
342 ((uint32_t *)buffer32->line[ega->displine])[((x * 18) + 32 + 17) & 2047] = (dat & 1) ? fg : bg;
343 }
344 }
345 else
346 {
347 if (ega->seqregs[1] & 1)
348 {
349 for (xx = 0; xx < 8; xx++)
350 ((uint32_t *)buffer32->line[ega->displine])[((x << 3) + 32 + xx) & 2047] = (dat & (0x80 >> xx)) ? fg : bg;
351 }
352 else
353 {
354 for (xx = 0; xx < 8; xx++)
355 ((uint32_t *)buffer32->line[ega->displine])[((x * 9) + 32 + xx) & 2047] = (dat & (0x80 >> xx)) ? fg : bg;
356 if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4))
357 ((uint32_t *)buffer32->line[ega->displine])[((x * 9) + 32 + 8) & 2047] = bg;
358 else
359 ((uint32_t *)buffer32->line[ega->displine])[((x * 9) + 32 + 8) & 2047] = (dat & 1) ? fg : bg;
360 }
361 }
362 ega->ma += 4;
363 ega->ma &= ega->vrammask;
364 }
365 }
366 }
367 else
368 {
369 switch (ega->gdcreg[5] & 0x20)
370 {
371 case 0x00:
372 if (ega->seqregs[1] & 8)
373 {
374 offset = ((8 - ega->scrollcache) << 1) + 16;
375 for (x = 0; x <= ega->hdisp; x++)
376 {
377 if (ega->sc & 1 && !(ega->crtc[0x17] & 1))
378 {
379 edat[0] = ega->vram[ega->ma | 0x8000];
380 edat[1] = ega->vram[ega->ma | 0x8001];
381 edat[2] = ega->vram[ega->ma | 0x8002];
382 edat[3] = ega->vram[ega->ma | 0x8003];
383 }
384 else
385 {
386 edat[0] = ega->vram[ega->ma];
387 edat[1] = ega->vram[ega->ma | 0x1];
388 edat[2] = ega->vram[ega->ma | 0x2];
389 edat[3] = ega->vram[ega->ma | 0x3];
390 }
391 ega->ma += 4;
392 ega->ma &= ega->vrammask;
394 dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2);
395 ((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]]];
396 ((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]]];
397 dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2);
398 ((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]]];
399 ((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]]];
400 dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2);
401 ((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]]];
402 ((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]]];
403 dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2);
404 ((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]]];
405 ((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]]];
406 }
407 }
408 else
409 {
410 offset = (8 - ega->scrollcache) + 24;
411 for (x = 0; x <= ega->hdisp; x++)
412 {
413 if (ega->sc & 1 && !(ega->crtc[0x17] & 1))
414 {
415 edat[0] = ega->vram[ega->ma | 0x8000];
416 edat[1] = ega->vram[ega->ma | 0x8001];
417 edat[2] = ega->vram[ega->ma | 0x8002];
418 edat[3] = ega->vram[ega->ma | 0x8003];
419 }
420 else
421 {
422 edat[0] = ega->vram[ega->ma];
423 edat[1] = ega->vram[ega->ma | 0x1];
424 edat[2] = ega->vram[ega->ma | 0x2];
425 edat[3] = ega->vram[ega->ma | 0x3];
426 }
427 ega->ma += 4;
428 ega->ma &= ega->vrammask;
430 dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2);
431 ((uint32_t *)buffer32->line[ega->displine])[(x << 3) + 7 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]];
432 ((uint32_t *)buffer32->line[ega->displine])[(x << 3) + 6 + offset] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]];
433 dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2);
434 ((uint32_t *)buffer32->line[ega->displine])[(x << 3) + 5 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]];
435 ((uint32_t *)buffer32->line[ega->displine])[(x << 3) + 4 + offset] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]];
436 dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2);
437 ((uint32_t *)buffer32->line[ega->displine])[(x << 3) + 3 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]];
438 ((uint32_t *)buffer32->line[ega->displine])[(x << 3) + 2 + offset] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]];
439 dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2);
440 ((uint32_t *)buffer32->line[ega->displine])[(x << 3) + 1 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]];
441 ((uint32_t *)buffer32->line[ega->displine])[(x << 3) + offset] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]];
442 }
443 }
444 break;
445 case 0x20:
446 offset = ((8 - ega->scrollcache) << 1) + 16;
447 for (x = 0; x <= ega->hdisp; x++)
448 {
449 if (ega->sc & 1 && !(ega->crtc[0x17] & 1))
450 {
451 edat[0] = ega->vram[(ega->ma << 1) + 0x8000];
452 edat[1] = ega->vram[(ega->ma << 1) + 0x8004];
453 }
454 else
455 {
456 edat[0] = ega->vram[(ega->ma << 1)];
457 edat[1] = ega->vram[(ega->ma << 1) + 4];
458 }
459 ega->ma += 4;
460 ega->ma &= ega->vrammask;
462 ((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]];
463 ((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]];
464 ((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]];
465 ((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]];
466 ((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]];
467 ((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]];
468 ((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]];
469 ((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]];
470 }
471 break;
472 }
473 }
474 if (ega->lastline < ega->displine)
475 ega->lastline = ega->displine;
476 }
478 ega->displine++;
479 if ((ega->stat & 8) && ((ega->displine & 15) == (ega->crtc[0x11] & 15)) && ega->vslines)
480 ega->stat &= ~8;
481 ega->vslines++;
482 if (ega->displine > 500)
483 ega->displine = 0;
484 }
485 else
486 {
487 ega->vidtime += ega->dispontime;
488 // if (output) printf("Display on %f\n",vidtime);
489 if (ega->dispon)
490 ega->stat &= ~1;
491 ega->linepos = 0;
492 if (ega->sc == (ega->crtc[11] & 31))
493 ega->con = 0;
494 if (ega->dispon)
495 {
496 if (ega->sc == (ega->crtc[9] & 31))
497 {
498 ega->sc = 0;
500 ega->maback += (ega->rowoffset << 3);
501 ega->maback &= ega->vrammask;
502 ega->ma = ega->maback;
503 }
504 else
505 {
506 ega->sc++;
507 ega->sc &= 31;
508 ega->ma = ega->maback;
509 }
510 }
511 ega->vc++;
512 ega->vc &= 1023;
513 // printf("Line now %i %i ma %05X\n",vc,displine,ma);
514 if (ega->vc == ega->split)
515 {
516 // printf("Split at line %i %i\n",displine,vc);
517 ega->ma = ega->maback = 0;
518 if (ega->attrregs[0x10] & 0x20)
519 ega->scrollcache = 0;
520 }
521 if (ega->vc == ega->dispend)
522 {
523 // printf("Display over at line %i %i\n",displine,vc);
524 ega->dispon=0;
525 if (ega->crtc[10] & 0x20) ega->cursoron = 0;
526 else ega->cursoron = ega->blink & 16;
527 if (!(ega->gdcreg[6] & 1) && !(ega->blink & 15))
528 fullchange = 2;
529 ega->blink++;
531 if (fullchange)
532 fullchange--;
533 }
534 if (ega->vc == ega->vsyncstart)
535 {
536 int wx, wy;
537 ega->dispon = 0;
538 // printf("Vsync on at line %i %i\n",displine,vc);
539 ega->stat |= 8;
540 if (ega->seqregs[1] & 8) x = ega->hdisp * ((ega->seqregs[1] & 1) ? 8 : 9) * 2;
541 else x = ega->hdisp * ((ega->seqregs[1] & 1) ? 8 : 9);
542 // pclog("Cursor %02X %02X\n",crtc[10],crtc[11]);
543 // pclog("Firstline %i Lastline %i wx %i %i\n",firstline,lastline,wx,oddeven);
544 // doblit();
545 if (x != xsize || (ega->lastline - ega->firstline) != ysize)
546 {
547 xsize = x;
548 ysize = ega->lastline - ega->firstline;
549 if (xsize < 64) xsize = 656;
550 if (ysize < 32) ysize = 200;
551 if (ega->vres)
552 updatewindowsize(xsize, ysize << 1);
553 else
554 updatewindowsize(xsize, ysize);
555 }
557 startblit();
558 video_blit_memtoscreen(32, 0, ega->firstline, ega->lastline, xsize, ega->lastline - ega->firstline);
559 endblit();
561 frames++;
563 ega->video_res_x = wx;
564 ega->video_res_y = wy + 1;
565 if (!(ega->gdcreg[6] & 1)) /*Text mode*/
566 {
567 ega->video_res_x /= (ega->seqregs[1] & 1) ? 8 : 9;
568 ega->video_res_y /= (ega->crtc[9] & 31) + 1;
569 ega->video_bpp = 0;
570 }
571 else
572 {
573 if (ega->crtc[9] & 0x80)
574 ega->video_res_y /= 2;
575 if (!(ega->crtc[0x17] & 1))
576 ega->video_res_y *= 2;
577 ega->video_res_y /= (ega->crtc[9] & 31) + 1;
578 if (ega->seqregs[1] & 8)
579 ega->video_res_x /= 2;
580 ega->video_bpp = (ega->gdcreg[5] & 0x20) ? 2 : 4;
581 }
583 // wakeupblit();
584 readflash=0;
585 //framecount++;
586 ega->firstline = 2000;
587 ega->lastline = 0;
589 ega->maback = ega->ma = (ega->crtc[0xc] << 8)| ega->crtc[0xd];
590 ega->ca = (ega->crtc[0xe] << 8) | ega->crtc[0xf];
591 ega->ma <<= 2;
592 ega->maback <<= 2;
593 ega->ca <<= 2;
594 changeframecount = 2;
595 ega->vslines = 0;
596 }
597 if (ega->vc == ega->vtotal)
598 {
599 ega->vc = 0;
600 ega->sc = 0;
601 ega->dispon = 1;
602 ega->displine = 0;
603 ega->scrollcache = ega->attrregs[0x13] & 7;
604 }
605 if (ega->sc == (ega->crtc[10] & 31))
606 ega->con = 1;
607 }
608 }
611 void ega_write(uint32_t addr, uint8_t val, void *p)
612 {
613 ega_t *ega = (ega_t *)p;
614 uint8_t vala, valb, valc, vald;
616 egawrites++;
617 cycles -= video_timing_b;
618 cycles_lost += video_timing_b;
620 if (addr >= 0xB0000) addr &= 0x7fff;
621 else addr &= 0xffff;
623 if (!(ega->gdcreg[6] & 1))
624 fullchange = 2;
625 addr <<= 2;
627 // 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]);
628 switch (ega->writemode)
629 {
630 case 1:
631 if (ega->writemask & 1) ega->vram[addr] = ega->la;
632 if (ega->writemask & 2) ega->vram[addr | 0x1] = ega->lb;
633 if (ega->writemask & 4) ega->vram[addr | 0x2] = ega->lc;
634 if (ega->writemask & 8) ega->vram[addr | 0x3] = ega->ld;
635 break;
636 case 0:
637 if (ega->gdcreg[3] & 7)
638 val = ega_rotate[ega->gdcreg[3] & 7][val];
640 if (ega->gdcreg[8] == 0xff && !(ega->gdcreg[3] & 0x18) && !ega->gdcreg[1])
641 {
642 if (ega->writemask & 1) ega->vram[addr] = val;
643 if (ega->writemask & 2) ega->vram[addr | 0x1] = val;
644 if (ega->writemask & 4) ega->vram[addr | 0x2] = val;
645 if (ega->writemask & 8) ega->vram[addr | 0x3] = val;
646 }
647 else
648 {
649 if (ega->gdcreg[1] & 1) vala = (ega->gdcreg[0] & 1) ? 0xff : 0;
650 else vala = val;
651 if (ega->gdcreg[1] & 2) valb = (ega->gdcreg[0] & 2) ? 0xff : 0;
652 else valb = val;
653 if (ega->gdcreg[1] & 4) valc = (ega->gdcreg[0] & 4) ? 0xff : 0;
654 else valc = val;
655 if (ega->gdcreg[1] & 8) vald = (ega->gdcreg[0] & 8) ? 0xff : 0;
656 else vald = val;
657 // pclog("Write %02X %01X %02X %02X %02X %02X %02X\n",gdcreg[3]&0x18,writemask,vala,valb,valc,vald,gdcreg[8]);
658 switch (ega->gdcreg[3] & 0x18)
659 {
660 case 0: /*Set*/
661 if (ega->writemask & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]);
662 if (ega->writemask & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]);
663 if (ega->writemask & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]);
664 if (ega->writemask & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]);
665 break;
666 case 8: /*AND*/
667 if (ega->writemask & 1) ega->vram[addr] = (vala | ~ega->gdcreg[8]) & ega->la;
668 if (ega->writemask & 2) ega->vram[addr | 0x1] = (valb | ~ega->gdcreg[8]) & ega->lb;
669 if (ega->writemask & 4) ega->vram[addr | 0x2] = (valc | ~ega->gdcreg[8]) & ega->lc;
670 if (ega->writemask & 8) ega->vram[addr | 0x3] = (vald | ~ega->gdcreg[8]) & ega->ld;
671 break;
672 case 0x10: /*OR*/
673 if (ega->writemask & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | ega->la;
674 if (ega->writemask & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | ega->lb;
675 if (ega->writemask & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | ega->lc;
676 if (ega->writemask & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | ega->ld;
677 break;
678 case 0x18: /*XOR*/
679 if (ega->writemask & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) ^ ega->la;
680 if (ega->writemask & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) ^ ega->lb;
681 if (ega->writemask & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) ^ ega->lc;
682 if (ega->writemask & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) ^ ega->ld;
683 break;
684 }
685 // pclog("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr);
686 }
687 break;
688 case 2:
689 if (!(ega->gdcreg[3] & 0x18) && !ega->gdcreg[1])
690 {
691 if (ega->writemask & 1) ega->vram[addr] = (((val & 1) ? 0xff : 0) & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]);
692 if (ega->writemask & 2) ega->vram[addr | 0x1] = (((val & 2) ? 0xff : 0) & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]);
693 if (ega->writemask & 4) ega->vram[addr | 0x2] = (((val & 4) ? 0xff : 0) & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]);
694 if (ega->writemask & 8) ega->vram[addr | 0x3] = (((val & 8) ? 0xff : 0) & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]);
695 }
696 else
697 {
698 vala = ((val & 1) ? 0xff : 0);
699 valb = ((val & 2) ? 0xff : 0);
700 valc = ((val & 4) ? 0xff : 0);
701 vald = ((val & 8) ? 0xff : 0);
702 switch (ega->gdcreg[3] & 0x18)
703 {
704 case 0: /*Set*/
705 if (ega->writemask & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]);
706 if (ega->writemask & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]);
707 if (ega->writemask & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]);
708 if (ega->writemask & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]);
709 break;
710 case 8: /*AND*/
711 if (ega->writemask & 1) ega->vram[addr] = (vala | ~ega->gdcreg[8]) & ega->la;
712 if (ega->writemask & 2) ega->vram[addr | 0x1] = (valb | ~ega->gdcreg[8]) & ega->lb;
713 if (ega->writemask & 4) ega->vram[addr | 0x2] = (valc | ~ega->gdcreg[8]) & ega->lc;
714 if (ega->writemask & 8) ega->vram[addr | 0x3] = (vald | ~ega->gdcreg[8]) & ega->ld;
715 break;
716 case 0x10: /*OR*/
717 if (ega->writemask & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | ega->la;
718 if (ega->writemask & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | ega->lb;
719 if (ega->writemask & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | ega->lc;
720 if (ega->writemask & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | ega->ld;
721 break;
722 case 0x18: /*XOR*/
723 if (ega->writemask & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) ^ ega->la;
724 if (ega->writemask & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) ^ ega->lb;
725 if (ega->writemask & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) ^ ega->lc;
726 if (ega->writemask & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) ^ ega->ld;
727 break;
728 }
729 }
730 break;
731 }
732 }
734 uint8_t ega_read(uint32_t addr, void *p)
735 {
736 ega_t *ega = (ega_t *)p;
737 uint8_t temp, temp2, temp3, temp4;
738 egareads++;
739 cycles -= video_timing_b;
740 cycles_lost += video_timing_b;
741 // pclog("Readega %06X ",addr);
742 if (addr >= 0xb0000) addr &= 0x7fff;
743 else addr &= 0xffff;
744 addr <<= 2;
745 ega->la = ega->vram[addr];
746 ega->lb = ega->vram[addr | 0x1];
747 ega->lc = ega->vram[addr | 0x2];
748 ega->ld = ega->vram[addr | 0x3];
749 if (ega->readmode)
750 {
751 temp = (ega->colournocare & 1) ? 0xff : 0;
752 temp &= ega->la;
753 temp ^= (ega->colourcompare & 1) ? 0xff : 0;
754 temp2 = (ega->colournocare & 2) ? 0xff : 0;
755 temp2 &= ega->lb;
756 temp2 ^= (ega->colourcompare & 2) ? 0xff : 0;
757 temp3 = (ega->colournocare & 4) ? 0xff : 0;
758 temp3 &= ega->lc;
759 temp3 ^= (ega->colourcompare & 4) ? 0xff : 0;
760 temp4 = (ega->colournocare & 8) ? 0xff : 0;
761 temp4 &= ega->ld;
762 temp4 ^= (ega->colourcompare & 8) ? 0xff : 0;
763 return ~(temp | temp2 | temp3 | temp4);
764 }
765 return ega->vram[addr | ega->readplane];
766 }
768 void ega_init(ega_t *ega)
769 {
770 int c, d, e;
772 ega->vram = malloc(0x40000);
773 ega->vrammask = 0x3ffff;
775 for (c = 0; c < 256; c++)
776 {
777 e = c;
778 for (d = 0; d < 8; d++)
779 {
780 ega_rotate[d][c] = e;
781 e = (e >> 1) | ((e & 1) ? 0x80 : 0);
782 }
783 }
785 for (c = 0; c < 4; c++)
786 {
787 for (d = 0; d < 4; d++)
788 {
789 edatlookup[c][d] = 0;
790 if (c & 1) edatlookup[c][d] |= 1;
791 if (d & 1) edatlookup[c][d] |= 2;
792 if (c & 2) edatlookup[c][d] |= 0x10;
793 if (d & 2) edatlookup[c][d] |= 0x20;
794 }
795 }
797 for (c = 0; c < 256; c++)
798 {
799 pallook64[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa);
800 pallook64[c] += makecol32(((c >> 5) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 3) & 1) * 0x55);
801 pallook16[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa);
802 pallook16[c] += makecol32(((c >> 4) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 4) & 1) * 0x55);
803 if ((c & 0x17) == 6)
804 pallook16[c] = makecol32(0xaa, 0x55, 0);
805 }
806 ega->pallook = pallook16;
807 }
809 void *ega_standalone_init()
810 {
811 int c, d, e;
812 ega_t *ega = malloc(sizeof(ega_t));
813 memset(ega, 0, sizeof(ega_t));
815 rom_init(&ega->bios_rom, "roms/ibm_6277356_ega_card_u44_27128.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
817 if (ega->bios_rom.rom[0x3ffe] == 0xaa && ega->bios_rom.rom[0x3fff] == 0x55)
818 {
819 int c;
820 pclog("Read EGA ROM in reverse\n");
822 for (c = 0; c < 0x2000; c++)
823 {
824 uint8_t temp = ega->bios_rom.rom[c];
825 ega->bios_rom.rom[c] = ega->bios_rom.rom[0x3fff - c];
826 ega->bios_rom.rom[0x3fff - c] = temp;
827 }
828 }
830 ega_init(ega);
832 mem_mapping_add(&ega->mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, 0, ega);
833 timer_add(ega_poll, &ega->vidtime, TIMER_ALWAYS_ENABLED, ega);
834 io_sethandler(0x03a0, 0x0040, ega_in, NULL, NULL, ega_out, NULL, NULL, ega);
835 return ega;
836 }
838 static int ega_standalone_available()
839 {
840 return rom_present("roms/ibm_6277356_ega_card_u44_27128.bin");
841 }
843 void ega_close(void *p)
844 {
845 ega_t *ega = (ega_t *)p;
847 free(ega->vram);
848 free(ega);
849 }
851 void ega_speed_changed(void *p)
852 {
853 ega_t *ega = (ega_t *)p;
855 ega_recalctimings(ega);
856 }
858 device_t ega_device =
859 {
860 "EGA",
861 0,
862 ega_standalone_init,
863 ega_close,
864 ega_standalone_available,
865 ega_speed_changed,
866 NULL,
867 NULL
868 };
