1 /*Oak OTI067 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_oti067.h"
10 #include "vid_svga.h"
11 #include "acer386sx.h"
12 
13 typedef struct oti067_t
14 {
15         svga_t svga;
16 
17         rom_t bios_rom;
18 
19         int index;
20         uint8_t regs[32];
21 
22         uint8_t pos;
23         uint8_t dipswitch_val;
24 
25         uint32_t vram_size;
26         uint32_t vram_mask;
27 } oti067_t;
28 
oti067_out(uint16_t addr,uint8_t val,void * p)29 void oti067_out(uint16_t addr, uint8_t val, void *p)
30 {
31         oti067_t *oti067 = (oti067_t *)p;
32         svga_t *svga = &oti067->svga;
33         uint8_t old;
34 
35 //        pclog("oti067_out : %04X %02X  %02X %i\n", addr, val, ram[0x489], ins);
36 
37         if ((((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1)) addr ^= 0x60;
38 
39         switch (addr)
40         {
41                 case 0x3D4:
42                 svga->crtcreg = val & 0x3f;
43                 return;
44                 case 0x3D5:
45                 if (svga->crtcreg & 0x20)
46                         return;
47                 if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80))
48                         return;
49                 if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80))
50                         val = (svga->crtc[7] & ~0x10) | (val & 0x10);
51                 old = svga->crtc[svga->crtcreg];
52                 svga->crtc[svga->crtcreg] = val;
53                 if (old != val)
54                 {
55                         if (svga->crtcreg < 0xE || svga->crtcreg > 0x10)
56                         {
57                                 svga->fullchange = changeframecount;
58                                 svga_recalctimings(svga);
59                         }
60                 }
61                 break;
62 
63                 case 0x3DE:
64                 oti067->index = val & 0x1f;
65                 return;
66                 case 0x3DF:
67                 oti067->regs[oti067->index] = val;
68                 switch (oti067->index)
69                 {
70                         case 0xD:
71                         svga->vram_display_mask = (val & 0xc) ? oti067->vram_mask : 0x3ffff;
72                         if ((val & 0x80) && oti067->vram_size == 256)
73                                 mem_mapping_disable(&svga->mapping);
74                         else
75                                 mem_mapping_enable(&svga->mapping);
76                         if (!(val & 0x80))
77                                 svga->vram_display_mask = 0x3ffff;
78                         break;
79                         case 0x11:
80                         svga->read_bank = (val & 0xf) * 65536;
81                         svga->write_bank = (val >> 4) * 65536;
82                         break;
83                 }
84                 return;
85         }
86         svga_out(addr, val, svga);
87 }
88 
oti067_in(uint16_t addr,void * p)89 uint8_t oti067_in(uint16_t addr, void *p)
90 {
91         oti067_t *oti067 = (oti067_t *)p;
92         svga_t *svga = &oti067->svga;
93         uint8_t temp;
94 
95 //        if (addr != 0x3da && addr != 0x3ba) pclog("oti067_in : %04X ", addr);
96 
97         if ((((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1)) addr ^= 0x60;
98 
99         switch (addr)
100         {
101                 case 0x3D4:
102                 temp = svga->crtcreg;
103                 break;
104                 case 0x3D5:
105                 if (svga->crtcreg & 0x20)
106                         temp = 0xff;
107                 else
108                         temp = svga->crtc[svga->crtcreg];
109                 break;
110 
111                 case 0x3DE:
112                 temp = oti067->index | (2 << 5);
113                 break;
114                 case 0x3DF:
115                 if (oti067->index==0x10)     temp = oti067->dipswitch_val;
116                 else                         temp = oti067->regs[oti067->index];
117                 break;
118 
119                 default:
120                 temp = svga_in(addr, svga);
121                 break;
122         }
123 //        if (addr != 0x3da && addr != 0x3ba) pclog("%02X  %04X:%04X\n", temp, CS,pc);
124         return temp;
125 }
126 
oti067_pos_out(uint16_t addr,uint8_t val,void * p)127 void oti067_pos_out(uint16_t addr, uint8_t val, void *p)
128 {
129         oti067_t *oti067 = (oti067_t *)p;
130 
131         if ((val & 8) != (oti067->pos & 8))
132         {
133                 if (val & 8)
134                         io_sethandler(0x03c0, 0x0020, oti067_in, NULL, NULL, oti067_out, NULL, NULL, oti067);
135                 else
136                         io_removehandler(0x03c0, 0x0020, oti067_in, NULL, NULL, oti067_out, NULL, NULL, oti067);
137         }
138 
139         oti067->pos = val;
140 }
141 
oti067_pos_in(uint16_t addr,void * p)142 uint8_t oti067_pos_in(uint16_t addr, void *p)
143 {
144         oti067_t *oti067 = (oti067_t *)p;
145 
146         return oti067->pos;
147 }
148 
oti067_recalctimings(svga_t * svga)149 void oti067_recalctimings(svga_t *svga)
150 {
151         oti067_t *oti067 = (oti067_t *)svga->p;
152 
153         if (oti067->regs[0x14] & 0x08) svga->ma_latch |= 0x10000;
154         if (oti067->regs[0x0d] & 0x0c) svga->rowoffset <<= 1;
155         svga->interlace = oti067->regs[0x14] & 0x80;
156 }
157 
oti067_common_init(char * bios_fn,int vram_size)158 void *oti067_common_init(char *bios_fn, int vram_size)
159 {
160         oti067_t *oti067 = malloc(sizeof(oti067_t));
161         memset(oti067, 0, sizeof(oti067_t));
162 
163         rom_init(&oti067->bios_rom, bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
164 
165         oti067->vram_size = vram_size;
166         oti067->vram_mask = (vram_size << 10) - 1;
167 
168         svga_init(&oti067->svga, oti067, vram_size << 10,
169                    oti067_recalctimings,
170                    oti067_in, oti067_out,
171                    NULL,
172                    NULL);
173 
174         io_sethandler(0x03c0, 0x0020, oti067_in, NULL, NULL, oti067_out, NULL, NULL, oti067);
175         io_sethandler(0x46e8, 0x0001, oti067_pos_in, NULL, NULL, oti067_pos_out, NULL, NULL, oti067);
176 
177         oti067->svga.miscout = 1;
178 
179         oti067->dipswitch_val = 0x18;
180         return oti067;
181 }
182 
oti067_enable_disable(void * p,int enable)183 void oti067_enable_disable(void *p, int enable)
184 {
185         oti067_t *oti067 = (oti067_t *)p;
186 
187         mem_mapping_disable(&oti067->bios_rom.mapping);
188         io_removehandler(0x03c0, 0x0020, oti067_in, NULL, NULL, oti067_out, NULL, NULL, oti067);
189         io_removehandler(0x46e8, 0x0001, oti067_pos_in, NULL, NULL, oti067_pos_out, NULL, NULL, oti067);
190         mem_mapping_disable(&oti067->svga.mapping);
191         if (enable)
192         {
193                 mem_mapping_enable(&oti067->bios_rom.mapping);
194                 io_sethandler(0x03c0, 0x0020, oti067_in, NULL, NULL, oti067_out, NULL, NULL, oti067);
195                 io_sethandler(0x46e8, 0x0001, oti067_pos_in, NULL, NULL, oti067_pos_out, NULL, NULL, oti067);
196                 mem_mapping_enable(&oti067->svga.mapping);
197         }
198 }
199 
oti067_init()200 void *oti067_init()
201 {
202         int vram_size = device_get_config_int("memory");
203         return oti067_common_init("oti067/bios.bin", vram_size);
204 }
205 
oti067_acer386_init()206 void *oti067_acer386_init()
207 {
208         oti067_t *oti067 = oti067_common_init("acer386/oti067.bin", 512);
209 
210         acer386sx_set_oti067(oti067);
211 
212         return oti067;
213 }
214 
oti067_ama932j_init()215 void *oti067_ama932j_init()
216 {
217         oti067_t *oti067 = oti067_common_init("ama932j/oti067.bin", 512);
218 
219         oti067->dipswitch_val |= 0x20;
220         return oti067;
221 }
222 
oti067_available()223 static int oti067_available()
224 {
225         return rom_present("oti067/bios.bin");
226 }
227 
oti067_close(void * p)228 void oti067_close(void *p)
229 {
230         oti067_t *oti067 = (oti067_t *)p;
231 
232         svga_close(&oti067->svga);
233 
234         free(oti067);
235 }
236 
oti067_speed_changed(void * p)237 void oti067_speed_changed(void *p)
238 {
239         oti067_t *oti067 = (oti067_t *)p;
240 
241         svga_recalctimings(&oti067->svga);
242 }
243 
oti067_force_redraw(void * p)244 void oti067_force_redraw(void *p)
245 {
246         oti067_t *oti067 = (oti067_t *)p;
247 
248         oti067->svga.fullchange = changeframecount;
249 }
250 
oti067_add_status_info(char * s,int max_len,void * p)251 void oti067_add_status_info(char *s, int max_len, void *p)
252 {
253         oti067_t *oti067 = (oti067_t *)p;
254 
255         svga_add_status_info(s, max_len, &oti067->svga);
256 }
257 
258 static device_config_t oti067_config[] =
259 {
260         {
261                 .name = "memory",
262                 .description = "Memory size",
263                 .type = CONFIG_SELECTION,
264                 .selection =
265                 {
266                         {
267                                 .description = "256 kB",
268                                 .value = 256
269                         },
270                         {
271                                 .description = "512 kB",
272                                 .value = 512
273                         },
274                         {
275                                 .description = ""
276                         }
277                 },
278                 .default_int = 512
279         },
280         {
281                 .type = -1
282         }
283 };
284 
285 device_t oti067_device =
286 {
287         "Oak OTI-067",
288         0,
289         oti067_init,
290         oti067_close,
291         oti067_available,
292         oti067_speed_changed,
293         oti067_force_redraw,
294         oti067_add_status_info,
295         oti067_config
296 };
297 device_t oti067_acer386_device =
298 {
299         "Oak OTI-067 (Acermate 386SX/25N)",
300         0,
301         oti067_acer386_init,
302         oti067_close,
303         oti067_available,
304         oti067_speed_changed,
305         oti067_force_redraw,
306         oti067_add_status_info
307 };
308 device_t oti067_ama932j_device =
309 {
310         "Oak OTI-067 (AMA-932J)",
311         0,
312         oti067_ama932j_init,
313         oti067_close,
314         oti067_available,
315         oti067_speed_changed,
316         oti067_force_redraw,
317         oti067_add_status_info
318 };
319