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