PCem
view src/vid_tvga.c @ 154:d0d530adce12
Initial port to Linux (using Allegro).
64-bit fixes.
Some changes to aid portability.
A few other tweaks.
| author | TomW |
|---|---|
| date | Thu Sep 04 21:07:24 2014 +0100 |
| parents | cba58d4def81 |
| children |
line source
1 /*Trident TVGA (8900D) 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 "video.h"
9 #include "vid_svga.h"
10 #include "vid_svga_render.h"
11 #include "vid_tkd8001_ramdac.h"
12 #include "vid_tvga.h"
14 typedef struct tvga_t
15 {
16 mem_mapping_t linear_mapping;
17 mem_mapping_t accel_mapping;
19 svga_t svga;
20 tkd8001_ramdac_t ramdac;
22 rom_t bios_rom;
24 uint8_t tvga_3d8, tvga_3d9;
25 int oldmode;
26 uint8_t oldctrl1;
27 uint8_t oldctrl2, newctrl2;
29 int vram_size;
30 uint32_t vram_mask;
31 } tvga_t;
33 static uint8_t crtc_mask[0x40] =
34 {
35 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
36 0x7f, 0xff, 0x3f, 0x7f, 0xff, 0xff, 0xff, 0xff,
37 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xef,
38 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
39 0x7f, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x03,
40 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
41 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
42 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
43 };
45 void tvga_out(uint16_t addr, uint8_t val, void *p)
46 {
47 tvga_t *tvga = (tvga_t *)p;
48 svga_t *svga = &tvga->svga;
50 uint8_t old;
52 // pclog("tvga_out : %04X %02X %04X:%04X %i\n", addr, val, CS,pc, svga->bpp);
53 if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60;
55 switch (addr)
56 {
57 case 0x3C5:
58 switch (svga->seqaddr & 0xf)
59 {
60 case 0xB:
61 tvga->oldmode=1;
62 break;
63 case 0xC:
64 if (svga->seqregs[0xe] & 0x80)
65 svga->seqregs[0xc] = val;
66 break;
67 case 0xd:
68 if (tvga->oldmode)
69 tvga->oldctrl2 = val;
70 else
71 {
72 tvga->newctrl2 = val;
73 svga_recalctimings(svga);
74 }
75 break;
76 case 0xE:
77 if (tvga->oldmode)
78 tvga->oldctrl1 = val;
79 else
80 {
81 svga->seqregs[0xe] = val ^ 2;
82 svga->write_bank = (svga->seqregs[0xe] & 0xf) * 65536;
83 if (!(svga->gdcreg[0xf] & 1))
84 svga->read_bank = svga->write_bank;
85 }
86 return;
87 }
88 break;
90 case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9:
91 tkd8001_ramdac_out(addr, val, &tvga->ramdac, svga);
92 return;
94 case 0x3CF:
95 switch (svga->gdcaddr & 15)
96 {
97 case 0xE:
98 svga->gdcreg[0xe] = val ^ 2;
99 if ((svga->gdcreg[0xf] & 1) == 1)
100 svga->read_bank = (svga->gdcreg[0xe] & 0xf) * 65536;
101 break;
102 case 0xF:
103 if (val & 1) svga->read_bank = (svga->gdcreg[0xe] & 0xf) *65536;
104 else svga->read_bank = (svga->seqregs[0xe] & 0xf) *65536;
105 svga->write_bank = (svga->seqregs[0xe] & 0xf) * 65536;
106 break;
107 }
108 break;
109 case 0x3D4:
110 svga->crtcreg = val & 0x3f;
111 return;
112 case 0x3D5:
113 if (svga->crtcreg <= 7 && svga->crtc[0x11] & 0x80) return;
114 old = svga->crtc[svga->crtcreg];
115 val &= crtc_mask[svga->crtcreg];
116 svga->crtc[svga->crtcreg] = val;
117 // if (svga->crtcreg != 0xC && svga->crtcreg != 0xE && svga->crtcreg != 0xF) pclog("CRTC R%02X = %02X %04X:%04X\n", svga->crtcreg, val, CS, pc);
118 if (old != val)
119 {
120 if (svga->crtcreg < 0xE || svga->crtcreg > 0x10)
121 {
122 svga->fullchange = changeframecount;
123 svga_recalctimings(svga);
124 }
125 }
126 switch (svga->crtcreg)
127 {
128 case 0x1e:
129 svga->vrammask = (val & 0x80) ? tvga->vram_mask : 0x3ffff;
130 break;
131 }
132 return;
133 case 0x3D8:
134 tvga->tvga_3d8 = val;
135 if (svga->gdcreg[0xf] & 4)
136 {
137 svga->write_bank = (val & 0x1f) * 65536;
138 // pclog("SVGAWBANK 3D8 %08X %04X:%04X\n",svgawbank,CS,pc);
139 if (!(svga->gdcreg[0xf] & 1))
140 {
141 svga->read_bank = (val & 0x1f) * 65536;
142 // pclog("SVGARBANK 3D8 %08X %04X:%04X\n",svgarbank,CS,pc);
143 }
144 }
145 return;
146 case 0x3D9:
147 tvga->tvga_3d9=val;
148 if ((svga->gdcreg[0xf] & 5) == 5)
149 {
150 svga->read_bank = (val & 0x1F) * 65536;
151 // pclog("SVGARBANK 3D9 %08X %04X:%04X\n",svgarbank,CS,pc);
152 }
153 return;
154 }
155 svga_out(addr, val, svga);
156 }
158 uint8_t tvga_in(uint16_t addr, void *p)
159 {
160 tvga_t *tvga = (tvga_t *)p;
161 svga_t *svga = &tvga->svga;
163 // if (addr != 0x3da) pclog("tvga_in : %04X %04X:%04X\n", addr, CS,pc);
165 if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60;
167 switch (addr)
168 {
169 case 0x3C5:
170 if ((svga->seqaddr & 0xf) == 0xb)
171 {
172 // printf("Read Trident ID %04X:%04X %04X\n",CS,pc,readmemw(ss,SP));
173 tvga->oldmode = 0;
174 return 0x33; /*TVGA8900D*/
175 }
176 if ((svga->seqaddr & 0xf) == 0xc)
177 {
178 // printf("Read Trident Power Up 1 %04X:%04X %04X\n",CS,pc,readmemw(ss,SP));
179 // return 0x20; /*2 DRAM banks*/
180 }
181 if ((svga->seqaddr & 0xf) == 0xd)
182 {
183 if (tvga->oldmode) return tvga->oldctrl2;
184 return tvga->newctrl2;
185 }
186 if ((svga->seqaddr & 0xf) == 0xe)
187 {
188 if (tvga->oldmode)
189 return tvga->oldctrl1;
190 }
191 break;
192 case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9:
193 return tkd8001_ramdac_in(addr, &tvga->ramdac, svga);
194 case 0x3D4:
195 return svga->crtcreg;
196 case 0x3D5:
197 if (svga->crtcreg > 0x18 && svga->crtcreg < 0x1e)
198 return 0xff;
199 return svga->crtc[svga->crtcreg];
200 case 0x3d8:
201 return tvga->tvga_3d8;
202 case 0x3d9:
203 return tvga->tvga_3d9;
204 }
205 return svga_in(addr, svga);
206 }
208 void tvga_recalctimings(svga_t *svga)
209 {
210 tvga_t *tvga = (tvga_t *)svga->p;
211 if (!svga->rowoffset) svga->rowoffset = 0x100; /*This is the only sensible way I can see this being handled,
212 given that TVGA8900D has no overflow bits.
213 Some sort of overflow is required for 320x200x24 and 1024x768x16*/
214 if (svga->crtc[0x29] & 0x10)
215 svga->rowoffset += 0x100;
217 if (svga->bpp == 24)
218 svga->hdisp = (svga->crtc[1] + 1) * 8;
220 if ((svga->crtc[0x1e] & 0xA0) == 0xA0) svga->ma_latch |= 0x10000;
221 if ((svga->crtc[0x27] & 0x01) == 0x01) svga->ma_latch |= 0x20000;
222 if ((svga->crtc[0x27] & 0x02) == 0x02) svga->ma_latch |= 0x40000;
224 if (tvga->oldctrl2 & 0x10)
225 {
226 svga->rowoffset <<= 1;
227 svga->ma_latch <<= 1;
228 }
229 if (svga->gdcreg[0xf] & 0x08)
230 {
231 svga->htotal *= 2;
232 svga->hdisp *= 2;
233 svga->hdisp_time *= 2;
234 }
236 svga->interlace = svga->crtc[0x1e] & 4;
237 if (svga->interlace)
238 svga->rowoffset >>= 1;
240 switch (((svga->miscout >> 2) & 3) | ((tvga->newctrl2 << 2) & 4))
241 {
242 case 2: svga->clock = cpuclock/44900000.0; break;
243 case 3: svga->clock = cpuclock/36000000.0; break;
244 case 4: svga->clock = cpuclock/57272000.0; break;
245 case 5: svga->clock = cpuclock/65000000.0; break;
246 case 6: svga->clock = cpuclock/50350000.0; break;
247 case 7: svga->clock = cpuclock/40000000.0; break;
248 }
250 if (tvga->oldctrl2 & 0x10)
251 {
252 switch (svga->bpp)
253 {
254 case 8:
255 svga->render = svga_render_8bpp_highres;
256 break;
257 case 15:
258 svga->render = svga_render_15bpp_highres;
259 svga->hdisp /= 2;
260 break;
261 case 16:
262 svga->render = svga_render_16bpp_highres;
263 svga->hdisp /= 2;
264 break;
265 case 24:
266 svga->render = svga_render_24bpp_highres;
267 svga->hdisp /= 3;
268 break;
269 }
270 svga->lowres = 0;
271 }
272 }
274 void *tvga8900d_init()
275 {
276 tvga_t *tvga = malloc(sizeof(tvga_t));
277 memset(tvga, 0, sizeof(tvga_t));
279 tvga->vram_size = device_get_config_int("memory") << 10;
280 tvga->vram_mask = tvga->vram_size - 1;
282 rom_init(&tvga->bios_rom, "roms/TRIDENT.BIN", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
284 svga_init(&tvga->svga, tvga, tvga->vram_size,
285 tvga_recalctimings,
286 tvga_in, tvga_out,
287 NULL,
288 NULL);
290 io_sethandler(0x03c0, 0x0020, tvga_in, NULL, NULL, tvga_out, NULL, NULL, tvga);
292 return tvga;
293 }
295 static int tvga8900d_available()
296 {
297 return rom_present("roms/TRIDENT.BIN");
298 }
300 void tvga_close(void *p)
301 {
302 tvga_t *tvga = (tvga_t *)p;
304 svga_close(&tvga->svga);
306 free(tvga);
307 }
309 void tvga_speed_changed(void *p)
310 {
311 tvga_t *tvga = (tvga_t *)p;
313 svga_recalctimings(&tvga->svga);
314 }
316 void tvga_force_redraw(void *p)
317 {
318 tvga_t *tvga = (tvga_t *)p;
320 tvga->svga.fullchange = changeframecount;
321 }
323 void tvga_add_status_info(char *s, int max_len, void *p)
324 {
325 tvga_t *tvga = (tvga_t *)p;
327 svga_add_status_info(s, max_len, &tvga->svga);
328 }
330 static device_config_t tvga_config[] =
331 {
332 {
333 .name = "memory",
334 .description = "Memory size",
335 .type = CONFIG_SELECTION,
336 .selection =
337 {
338 {
339 .description = "256 kB",
340 .value = 256
341 },
342 {
343 .description = "512 kB",
344 .value = 512
345 },
346 {
347 .description = "1 MB",
348 .value = 1024
349 },
350 /*Chip supports 2mb, but drivers are buggy*/
351 {
352 .description = ""
353 }
354 },
355 .default_int = 1024
356 },
357 {
358 .type = -1
359 }
360 };
362 device_t tvga8900d_device =
363 {
364 "Trident TVGA 8900D",
365 0,
366 tvga8900d_init,
367 tvga_close,
368 tvga8900d_available,
369 tvga_speed_changed,
370 tvga_force_redraw,
371 tvga_add_status_info,
372 tvga_config
373 };
