PCem

view src/vid_tvga.c @ 129:614f796ff7ed

Added configurable VRAM for Mach64, ET4000/w32p, Oak and Trident graphics cards.
author TomW
date Mon Jul 14 21:56:10 2014 +0100
parents 036dc3a418ac
children f22b6152c221
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 void tvga_out(uint16_t addr, uint8_t val, void *p)
34 {
35 tvga_t *tvga = (tvga_t *)p;
36 svga_t *svga = &tvga->svga;
38 uint8_t old;
40 // pclog("tvga_out : %04X %02X %04X:%04X %i\n", addr, val, CS,pc, svga->bpp);
41 if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60;
43 switch (addr)
44 {
45 case 0x3C5:
46 switch (svga->seqaddr & 0xf)
47 {
48 case 0xB:
49 tvga->oldmode=1;
50 break;
51 case 0xC:
52 if (svga->seqregs[0xe] & 0x80)
53 svga->seqregs[0xc] = val;
54 break;
55 case 0xd:
56 if (tvga->oldmode)
57 tvga->oldctrl2 = val;
58 else
59 {
60 tvga->newctrl2 = val;
61 svga_recalctimings(svga);
62 }
63 break;
64 case 0xE:
65 if (tvga->oldmode)
66 tvga->oldctrl1 = val;
67 else
68 {
69 svga->seqregs[0xe] = val ^ 2;
70 svga->write_bank = (svga->seqregs[0xe] & 0xf) * 65536;
71 if (!(svga->gdcreg[0xf] & 1))
72 svga->read_bank = svga->write_bank;
73 }
74 return;
75 }
76 break;
78 case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9:
79 tkd8001_ramdac_out(addr, val, &tvga->ramdac, svga);
80 return;
82 case 0x3CF:
83 switch (svga->gdcaddr & 15)
84 {
85 case 0xE:
86 svga->gdcreg[0xe] = val ^ 2;
87 if ((svga->gdcreg[0xf] & 1) == 1)
88 svga->read_bank = (svga->gdcreg[0xe] & 0xf) * 65536;
89 break;
90 case 0xF:
91 if (val & 1) svga->read_bank = (svga->gdcreg[0xe] & 0xf) *65536;
92 else svga->read_bank = (svga->seqregs[0xe] & 0xf) *65536;
93 svga->write_bank = (svga->seqregs[0xe] & 0xf) * 65536;
94 break;
95 }
96 break;
97 case 0x3D4:
98 svga->crtcreg = val & 0x3f;
99 return;
100 case 0x3D5:
101 if (svga->crtcreg <= 7 && svga->crtc[0x11] & 0x80) return;
102 old = svga->crtc[svga->crtcreg];
103 svga->crtc[svga->crtcreg] = val;
104 // if (svga->crtcreg != 0xC && svga->crtcreg != 0xE && svga->crtcreg != 0xF) pclog("CRTC R%02X = %02X %04X:%04X\n", svga->crtcreg, val, CS, pc);
105 if (old != val)
106 {
107 if (svga->crtcreg < 0xE || svga->crtcreg > 0x10)
108 {
109 svga->fullchange = changeframecount;
110 svga_recalctimings(svga);
111 }
112 }
113 switch (svga->crtcreg)
114 {
115 case 0x1e:
116 svga->vrammask = (val & 0x80) ? tvga->vram_mask : 0x3ffff;
117 break;
118 }
119 return;
120 case 0x3D8:
121 tvga->tvga_3d8 = val;
122 if (svga->gdcreg[0xf] & 4)
123 {
124 svga->write_bank = (val & 0x1f) * 65536;
125 // pclog("SVGAWBANK 3D8 %08X %04X:%04X\n",svgawbank,CS,pc);
126 if (!(svga->gdcreg[0xf] & 1))
127 {
128 svga->read_bank = (val & 0x1f) * 65536;
129 // pclog("SVGARBANK 3D8 %08X %04X:%04X\n",svgarbank,CS,pc);
130 }
131 }
132 return;
133 case 0x3D9:
134 tvga->tvga_3d9=val;
135 if ((svga->gdcreg[0xf] & 5) == 5)
136 {
137 svga->read_bank = (val & 0x1F) * 65536;
138 // pclog("SVGARBANK 3D9 %08X %04X:%04X\n",svgarbank,CS,pc);
139 }
140 return;
141 }
142 svga_out(addr, val, svga);
143 }
145 uint8_t tvga_in(uint16_t addr, void *p)
146 {
147 tvga_t *tvga = (tvga_t *)p;
148 svga_t *svga = &tvga->svga;
150 // if (addr != 0x3da) pclog("tvga_in : %04X %04X:%04X\n", addr, CS,pc);
152 if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60;
154 switch (addr)
155 {
156 case 0x3C5:
157 if ((svga->seqaddr & 0xf) == 0xb)
158 {
159 // printf("Read Trident ID %04X:%04X %04X\n",CS,pc,readmemw(ss,SP));
160 tvga->oldmode = 0;
161 return 0x33; /*TVGA8900D*/
162 }
163 if ((svga->seqaddr & 0xf) == 0xc)
164 {
165 // printf("Read Trident Power Up 1 %04X:%04X %04X\n",CS,pc,readmemw(ss,SP));
166 // return 0x20; /*2 DRAM banks*/
167 }
168 if ((svga->seqaddr & 0xf) == 0xd)
169 {
170 if (tvga->oldmode) return tvga->oldctrl2;
171 return tvga->newctrl2;
172 }
173 break;
174 case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9:
175 return tkd8001_ramdac_in(addr, &tvga->ramdac, svga);
176 case 0x3D4:
177 return svga->crtcreg;
178 case 0x3D5:
179 return svga->crtc[svga->crtcreg];
180 case 0x3d8:
181 return tvga->tvga_3d8;
182 case 0x3d9:
183 return tvga->tvga_3d9;
184 }
185 return svga_in(addr, svga);
186 }
188 void tvga_recalctimings(svga_t *svga)
189 {
190 tvga_t *tvga = (tvga_t *)svga->p;
191 if (!svga->rowoffset) svga->rowoffset = 0x100; /*This is the only sensible way I can see this being handled,
192 given that TVGA8900D has no overflow bits.
193 Some sort of overflow is required for 320x200x24 and 1024x768x16*/
194 if (svga->crtc[0x29] & 0x10)
195 svga->rowoffset += 0x100;
197 if (svga->bpp == 24)
198 svga->hdisp = (svga->crtc[1] + 1) * 8;
200 if ((svga->crtc[0x1e] & 0xA0) == 0xA0) svga->ma_latch |= 0x10000;
201 if ((svga->crtc[0x27] & 0x01) == 0x01) svga->ma_latch |= 0x20000;
202 if ((svga->crtc[0x27] & 0x02) == 0x02) svga->ma_latch |= 0x40000;
204 if (tvga->oldctrl2 & 0x10)
205 {
206 svga->rowoffset <<= 1;
207 svga->ma_latch <<= 1;
208 }
209 if (svga->gdcreg[0xf] & 0x08)
210 {
211 svga->htotal *= 2;
212 svga->hdisp *= 2;
213 svga->hdisp_time *= 2;
214 }
216 svga->interlace = svga->crtc[0x1e] & 4;
217 if (svga->interlace)
218 svga->rowoffset >>= 1;
220 switch (((svga->miscout >> 2) & 3) | ((tvga->newctrl2 << 2) & 4))
221 {
222 case 2: svga->clock = cpuclock/44900000.0; break;
223 case 3: svga->clock = cpuclock/36000000.0; break;
224 case 4: svga->clock = cpuclock/57272000.0; break;
225 case 5: svga->clock = cpuclock/65000000.0; break;
226 case 6: svga->clock = cpuclock/50350000.0; break;
227 case 7: svga->clock = cpuclock/40000000.0; break;
228 }
230 if (tvga->oldctrl2 & 0x10)
231 {
232 switch (svga->bpp)
233 {
234 case 8:
235 svga->render = svga_render_8bpp_highres;
236 break;
237 case 15:
238 svga->render = svga_render_15bpp_highres;
239 svga->hdisp /= 2;
240 break;
241 case 16:
242 svga->render = svga_render_16bpp_highres;
243 svga->hdisp /= 2;
244 break;
245 case 24:
246 svga->render = svga_render_24bpp_highres;
247 svga->hdisp /= 3;
248 break;
249 }
250 svga->lowres = 0;
251 }
252 }
254 void *tvga8900d_init()
255 {
256 tvga_t *tvga = malloc(sizeof(tvga_t));
257 memset(tvga, 0, sizeof(tvga_t));
259 tvga->vram_size = device_get_config_int("memory") << 10;
260 tvga->vram_mask = tvga->vram_size - 1;
262 rom_init(&tvga->bios_rom, "roms/trident.bin", 0xc0000, 0x8000, 0x7fff, 0, 0);
264 svga_init(&tvga->svga, tvga, tvga->vram_size,
265 tvga_recalctimings,
266 tvga_in, tvga_out,
267 NULL,
268 NULL);
270 io_sethandler(0x03c0, 0x0020, tvga_in, NULL, NULL, tvga_out, NULL, NULL, tvga);
272 return tvga;
273 }
275 static int tvga8900d_available()
276 {
277 return rom_present("roms/trident.bin");
278 }
280 void tvga_close(void *p)
281 {
282 tvga_t *tvga = (tvga_t *)p;
284 svga_close(&tvga->svga);
286 free(tvga);
287 }
289 void tvga_speed_changed(void *p)
290 {
291 tvga_t *tvga = (tvga_t *)p;
293 svga_recalctimings(&tvga->svga);
294 }
296 void tvga_force_redraw(void *p)
297 {
298 tvga_t *tvga = (tvga_t *)p;
300 tvga->svga.fullchange = changeframecount;
301 }
303 int tvga_add_status_info(char *s, int max_len, void *p)
304 {
305 tvga_t *tvga = (tvga_t *)p;
307 return svga_add_status_info(s, max_len, &tvga->svga);
308 }
310 static device_config_t tvga_config[] =
311 {
312 {
313 .name = "memory",
314 .description = "Memory size",
315 .type = CONFIG_SELECTION,
316 .selection =
317 {
318 {
319 .description = "256 kB",
320 .value = 256
321 },
322 {
323 .description = "512 kB",
324 .value = 512
325 },
326 {
327 .description = "1 MB",
328 .value = 1024
329 },
330 /*Chip supports 2mb, but drivers are buggy*/
331 {
332 .description = ""
333 }
334 },
335 .default_int = 1024
336 },
337 {
338 .type = -1
339 }
340 };
342 device_t tvga8900d_device =
343 {
344 "Trident TVGA 8900D",
345 0,
346 tvga8900d_init,
347 tvga_close,
348 tvga8900d_available,
349 tvga_speed_changed,
350 tvga_force_redraw,
351 tvga_add_status_info,
352 tvga_config
353 };