1 /*ET4000 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_unk_ramdac.h"
12
13 #include "vid_et4000.h"
14
15 typedef struct et4000_t
16 {
17 svga_t svga;
18 unk_ramdac_t ramdac;
19
20 rom_t bios_rom;
21
22 uint8_t banking;
23 uint8_t port_22cb_val;
24 uint8_t port_32cb_val;
25 int get_korean_font_enabled;
26 int get_korean_font_index;
27 uint16_t get_korean_font_base;
28 } et4000_t;
29
30 static uint8_t crtc_mask[0x40] =
31 {
32 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
33 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
34 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
35 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
37 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
38 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff,
39 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
40 };
41
et4000_out(uint16_t addr,uint8_t val,void * p)42 void et4000_out(uint16_t addr, uint8_t val, void *p)
43 {
44 et4000_t *et4000 = (et4000_t *)p;
45 svga_t *svga = &et4000->svga;
46
47 uint8_t old;
48
49 if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1))
50 addr ^= 0x60;
51
52 // pclog("ET4000 out %04X %02X\n", addr, val);
53
54 switch (addr)
55 {
56 case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9:
57 unk_ramdac_out(addr, val, &et4000->ramdac, svga);
58 return;
59
60 case 0x3CD: /*Banking*/
61 svga->write_bank = (val & 0xf) * 0x10000;
62 svga->read_bank = ((val >> 4) & 0xf) * 0x10000;
63 et4000->banking = val;
64 // pclog("Banking write %08X %08X %02X\n", svga->write_bank, svga->read_bank, val);
65 return;
66 case 0x3D4:
67 svga->crtcreg = val & 0x3f;
68 return;
69 case 0x3D5:
70 if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80))
71 return;
72 if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80))
73 val = (svga->crtc[7] & ~0x10) | (val & 0x10);
74 old = svga->crtc[svga->crtcreg];
75 val &= crtc_mask[svga->crtcreg];
76 svga->crtc[svga->crtcreg] = val;
77 if (old != val)
78 {
79 if (svga->crtcreg < 0xE || svga->crtcreg > 0x10)
80 {
81 svga->fullchange = changeframecount;
82 svga_recalctimings(svga);
83 }
84 }
85 break;
86 }
87 svga_out(addr, val, svga);
88 }
89
et4000k_out(uint16_t addr,uint8_t val,void * p)90 void et4000k_out(uint16_t addr, uint8_t val, void *p)
91 {
92 et4000_t *et4000 = (et4000_t *)p;
93
94 // pclog("ET4000k out %04X %02X\n", addr, val);
95
96 switch (addr)
97 {
98 case 0x22CB:
99 et4000->port_22cb_val = (et4000->port_22cb_val & 0xF0) | (val & 0x0F);
100 et4000->get_korean_font_enabled = val & 7;
101 if (et4000->get_korean_font_enabled == 3)
102 et4000->get_korean_font_index = 0;
103 break;
104 case 0x22CF:
105 switch (et4000->get_korean_font_enabled)
106 {
107 case 1:
108 et4000->get_korean_font_base = ((val & 0x7F) << 7) | (et4000->get_korean_font_base & 0x7F);
109 break;
110 case 2:
111 et4000->get_korean_font_base = (et4000->get_korean_font_base & 0x3F80) | (val & 0x7F) | (((val ^ 0x80) & 0x80) << 8);
112 break;
113 case 3:
114 if ((et4000->port_32cb_val & 0x30) == 0x20 && (et4000->get_korean_font_base & 0x7F) > 0x20 && (et4000->get_korean_font_base & 0x7F) < 0x7F)
115 {
116 switch (et4000->get_korean_font_base & 0x3F80)
117 {
118 case 0x2480:
119 if (et4000->get_korean_font_index < 16)
120 fontdatksc5601_user[(et4000->get_korean_font_base & 0x7F) - 0x20][et4000->get_korean_font_index] = val;
121 else if (et4000->get_korean_font_index >= 24 && et4000->get_korean_font_index < 40)
122 fontdatksc5601_user[(et4000->get_korean_font_base & 0x7F) - 0x20][et4000->get_korean_font_index - 8] = val;
123 break;
124 case 0x3F00:
125 if (et4000->get_korean_font_index < 16)
126 fontdatksc5601_user[96 + (et4000->get_korean_font_base & 0x7F) - 0x20][et4000->get_korean_font_index] = val;
127 else if (et4000->get_korean_font_index >= 24 && et4000->get_korean_font_index < 40)
128 fontdatksc5601_user[96 + (et4000->get_korean_font_base & 0x7F) - 0x20][et4000->get_korean_font_index - 8] = val;
129 break;
130 }
131 et4000->get_korean_font_index++;
132 }
133 break;
134 }
135 break;
136 case 0x32CB:
137 et4000->port_32cb_val = val;
138 svga_recalctimings(&et4000->svga);
139 break;
140 }
141 }
142
et4000_in(uint16_t addr,void * p)143 uint8_t et4000_in(uint16_t addr, void *p)
144 {
145 et4000_t *et4000 = (et4000_t *)p;
146 svga_t *svga = &et4000->svga;
147
148 if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1))
149 addr ^= 0x60;
150
151 // if (addr != 0x3da) pclog("IN ET4000 %04X\n", addr);
152
153 switch (addr)
154 {
155 case 0x3C5:
156 if ((svga->seqaddr & 0xf) == 7) return svga->seqregs[svga->seqaddr & 0xf] | 4;
157 break;
158
159 case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9:
160 return unk_ramdac_in(addr, &et4000->ramdac, svga);
161
162 case 0x3CD: /*Banking*/
163 return et4000->banking;
164 case 0x3D4:
165 return svga->crtcreg;
166 case 0x3D5:
167 return svga->crtc[svga->crtcreg];
168 }
169 return svga_in(addr, svga);
170 }
171
et4000k_in(uint16_t addr,void * p)172 uint8_t et4000k_in(uint16_t addr, void *p)
173 {
174 uint8_t val = 0xFF;
175 et4000_t *et4000 = (et4000_t *)p;
176
177 // if (addr != 0x3da) pclog("IN ET4000 %04X\n", addr);
178
179 switch (addr)
180 {
181 case 0x22CB:
182 return et4000->port_22cb_val;
183 case 0x22CF:
184 val = 0;
185 switch (et4000->get_korean_font_enabled)
186 {
187 case 3:
188 if ((et4000->port_32cb_val & 0x30) == 0x30)
189 {
190 val = fontdatksc5601[et4000->get_korean_font_base][et4000->get_korean_font_index++];
191 et4000->get_korean_font_index &= 0x1F;
192 }
193 else if ((et4000->port_32cb_val & 0x30) == 0x20 && (et4000->get_korean_font_base & 0x7F) > 0x20 && (et4000->get_korean_font_base & 0x7F) < 0x7F)
194 {
195 switch (et4000->get_korean_font_base & 0x3F80)
196 {
197 case 0x2480:
198 if (et4000->get_korean_font_index < 16)
199 val = fontdatksc5601_user[(et4000->get_korean_font_base & 0x7F) - 0x20][et4000->get_korean_font_index];
200 else if (et4000->get_korean_font_index >= 24 && et4000->get_korean_font_index < 40)
201 val = fontdatksc5601_user[(et4000->get_korean_font_base & 0x7F) - 0x20][et4000->get_korean_font_index - 8];
202 break;
203 case 0x3F00:
204 if (et4000->get_korean_font_index < 16)
205 val = fontdatksc5601_user[96 + (et4000->get_korean_font_base & 0x7F) - 0x20][et4000->get_korean_font_index];
206 else if (et4000->get_korean_font_index >= 24 && et4000->get_korean_font_index < 40)
207 val = fontdatksc5601_user[96 + (et4000->get_korean_font_base & 0x7F) - 0x20][et4000->get_korean_font_index - 8];
208 break;
209 }
210 et4000->get_korean_font_index++;
211 et4000->get_korean_font_index %= 72;
212 }
213 break;
214 case 4:
215 val = 0x0F;
216 break;
217 }
218 return val;
219 case 0x32CB:
220 return et4000->port_32cb_val;
221 }
222
223 return 0xff;
224 }
225
et4000_recalctimings(svga_t * svga)226 void et4000_recalctimings(svga_t *svga)
227 {
228 svga->ma_latch |= (svga->crtc[0x33]&3)<<16;
229 if (svga->crtc[0x35] & 1) svga->vblankstart += 0x400;
230 if (svga->crtc[0x35] & 2) svga->vtotal += 0x400;
231 if (svga->crtc[0x35] & 4) svga->dispend += 0x400;
232 if (svga->crtc[0x35] & 8) svga->vsyncstart += 0x400;
233 if (svga->crtc[0x35] & 0x10) svga->split += 0x400;
234 if (!svga->rowoffset) svga->rowoffset = 0x100;
235 if (svga->crtc[0x3f] & 1) svga->htotal += 256;
236 if (svga->attrregs[0x16] & 0x20) svga->hdisp <<= 1;
237
238 // pclog("Rowoffset %i\n",svga_rowoffset);
239
240 switch (((svga->miscout >> 2) & 3) | ((svga->crtc[0x34] << 1) & 4))
241 {
242 case 0: case 1: break;
243 case 3: svga->clock = cpuclock / 40000000.0; break;
244 case 5: svga->clock = cpuclock / 65000000.0; break;
245 default: svga->clock = cpuclock / 36000000.0; break;
246 }
247
248 switch (svga->bpp)
249 {
250 case 15: case 16:
251 svga->hdisp /= 2;
252 break;
253 case 24:
254 svga->hdisp /= 3;
255 break;
256 }
257 }
258
et4000k_recalctimings(svga_t * svga)259 void et4000k_recalctimings(svga_t *svga)
260 {
261 et4000_t *et4000 = (et4000_t *)svga->p;
262
263 et4000_recalctimings(svga);
264
265 if (svga->render == svga_render_text_80 && ((svga->crtc[0x37] & 0x0A) == 0x0A))
266 {
267 if((et4000->port_32cb_val & 0xB4) == ((svga->crtc[0x37] & 3) == 2 ? 0xB4 : 0xB0))
268 {
269 svga->render = svga_render_text_80_ksc5601;
270 }
271 }
272 }
273
et4000_init()274 void *et4000_init()
275 {
276 et4000_t *et4000 = malloc(sizeof(et4000_t));
277 memset(et4000, 0, sizeof(et4000_t));
278
279 rom_init(&et4000->bios_rom, "et4000.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
280
281 io_sethandler(0x03c0, 0x0020, et4000_in, NULL, NULL, et4000_out, NULL, NULL, et4000);
282
283 svga_init(&et4000->svga, et4000, 1 << 20, /*1mb*/
284 et4000_recalctimings,
285 et4000_in, et4000_out,
286 NULL,
287 NULL);
288
289 return et4000;
290 }
291
et4000k_init()292 void *et4000k_init()
293 {
294 et4000_t *et4000 = malloc(sizeof(et4000_t));
295 memset(et4000, 0, sizeof(et4000_t));
296
297 rom_init(&et4000->bios_rom, "tgkorvga.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
298 loadfont("tg_ksc5601.rom", 6);
299
300 io_sethandler(0x03c0, 0x0020, et4000_in, NULL, NULL, et4000_out, NULL, NULL, et4000);
301
302 io_sethandler(0x22cb, 0x0001, et4000k_in, NULL, NULL, et4000k_out, NULL, NULL, et4000);
303 io_sethandler(0x22cf, 0x0001, et4000k_in, NULL, NULL, et4000k_out, NULL, NULL, et4000);
304 io_sethandler(0x32cb, 0x0001, et4000k_in, NULL, NULL, et4000k_out, NULL, NULL, et4000);
305 et4000->port_22cb_val = 0x60;
306 et4000->port_32cb_val = 0;
307
308 svga_init(&et4000->svga, et4000, 1 << 20, /*1mb*/
309 et4000k_recalctimings,
310 et4000k_in, et4000k_out,
311 NULL,
312 NULL);
313
314 et4000->svga.ksc5601_sbyte_mask = 0x80;
315
316 return et4000;
317 }
318
et4000_available()319 static int et4000_available()
320 {
321 return rom_present("et4000.bin");
322 }
323
et4000k_available()324 static int et4000k_available()
325 {
326 return rom_present("tgkorvga.bin") && rom_present("tg_ksc5601.rom");;
327 }
328
et4000_close(void * p)329 void et4000_close(void *p)
330 {
331 et4000_t *et4000 = (et4000_t *)p;
332
333 svga_close(&et4000->svga);
334
335 free(et4000);
336 }
337
et4000_speed_changed(void * p)338 void et4000_speed_changed(void *p)
339 {
340 et4000_t *et4000 = (et4000_t *)p;
341
342 svga_recalctimings(&et4000->svga);
343 }
344
et4000_force_redraw(void * p)345 void et4000_force_redraw(void *p)
346 {
347 et4000_t *et4000 = (et4000_t *)p;
348
349 et4000->svga.fullchange = changeframecount;
350 }
351
et4000_add_status_info(char * s,int max_len,void * p)352 void et4000_add_status_info(char *s, int max_len, void *p)
353 {
354 et4000_t *et4000 = (et4000_t *)p;
355
356 svga_add_status_info(s, max_len, &et4000->svga);
357 }
358
359 device_t et4000_device =
360 {
361 "Tseng Labs ET4000AX",
362 0,
363 et4000_init,
364 et4000_close,
365 et4000_available,
366 et4000_speed_changed,
367 et4000_force_redraw,
368 et4000_add_status_info
369 };
370
371 device_t et4000k_device =
372 {
373 "Trigem Korean VGA(Tseng Labs ET4000AX)",
374 0,
375 et4000k_init,
376 et4000_close,
377 et4000k_available,
378 et4000_speed_changed,
379 et4000_force_redraw,
380 et4000_add_status_info
381 };
382