PCem

view src/vid_s3.c @ 121:173e1f058566

Fixed cursor in interlaced modes on S3 Vision864/Trio32/Trio64.
author TomW
date Wed Jul 09 22:12:59 2014 +0100
parents 47132154ffe7
children 84742b645324
line source
1 /*S3 emulation*/
2 #include <stdlib.h>
3 #include "ibm.h"
4 #include "device.h"
5 #include "io.h"
6 #include "mem.h"
7 #include "pci.h"
8 #include "rom.h"
9 #include "video.h"
10 #include "vid_s3.h"
11 #include "vid_svga.h"
12 #include "vid_svga_render.h"
13 #include "vid_sdac_ramdac.h"
15 enum
16 {
17 S3_VISION864,
18 S3_TRIO32,
19 S3_TRIO64
20 };
22 enum
23 {
24 VRAM_4MB = 0,
25 VRAM_8MB = 3,
26 VRAM_2MB = 4,
27 VRAM_1MB = 6,
28 VRAM_512KB = 7
29 };
31 typedef struct s3_t
32 {
33 mem_mapping_t linear_mapping;
34 mem_mapping_t mmio_mapping;
36 rom_t bios_rom;
38 svga_t svga;
39 sdac_ramdac_t ramdac;
41 uint8_t bank;
42 uint8_t ma_ext;
43 int width;
44 int bpp;
46 int chip;
48 uint8_t id, id_ext, id_ext_pci;
50 int packed_mmio;
52 uint32_t linear_base, linear_size;
54 uint8_t pci_regs[256];
56 uint32_t vram_mask;
58 float (*getclock)(int clock, void *p);
59 void *getclock_p;
61 struct
62 {
63 uint8_t subsys_cntl;
64 uint8_t setup_md;
65 uint8_t advfunc_cntl;
66 uint16_t cur_y;
67 uint16_t cur_x;
68 int16_t desty_axstp;
69 int16_t destx_distp;
70 int16_t err_term;
71 int16_t maj_axis_pcnt;
72 uint16_t cmd;
73 uint16_t short_stroke;
74 uint32_t bkgd_color;
75 uint32_t frgd_color;
76 uint32_t wrt_mask;
77 uint32_t rd_mask;
78 uint32_t color_cmp;
79 uint8_t bkgd_mix;
80 uint8_t frgd_mix;
81 uint16_t multifunc_cntl;
82 uint16_t multifunc[16];
83 uint8_t pix_trans[4];
85 int cx, cy;
86 int sx, sy;
87 int dx, dy;
88 uint32_t src, dest, pattern;
89 int pix_trans_count;
91 uint32_t dat_buf;
92 int dat_count;
93 } accel;
94 } s3_t;
96 void s3_updatemapping();
98 void s3_accel_write(uint32_t addr, uint8_t val, void *p);
99 void s3_accel_write_w(uint32_t addr, uint16_t val, void *p);
100 void s3_accel_write_l(uint32_t addr, uint32_t val, void *p);
101 uint8_t s3_accel_read(uint32_t addr, void *p);
104 void s3_out(uint16_t addr, uint8_t val, void *p)
105 {
106 s3_t *s3 = (s3_t *)p;
107 svga_t *svga = &s3->svga;
108 uint8_t old;
110 if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1))
111 addr ^= 0x60;
113 // pclog("S3 out %04X %02X %04x:%08x\n", addr, val, CS, pc);
115 switch (addr)
116 {
117 case 0x3c5:
118 if (svga->seqaddr >= 0x10 && svga->seqaddr < 0x20)
119 {
120 svga->seqregs[svga->seqaddr] = val;
121 switch (svga->seqaddr)
122 {
123 case 0x12: case 0x13:
124 svga_recalctimings(svga);
125 return;
126 }
127 }
128 if (svga->seqaddr == 4) /*Chain-4 - update banking*/
129 {
130 if (val & 8) svga->write_bank = svga->read_bank = s3->bank << 16;
131 else svga->write_bank = svga->read_bank = s3->bank << 14;
132 }
133 break;
135 case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9:
136 // pclog("Write RAMDAC %04X %02X %04X:%04X\n", addr, val, CS, pc);
137 sdac_ramdac_out(addr, val, &s3->ramdac, svga);
138 return;
140 case 0x3D4:
141 svga->crtcreg = val & 0x7f;
142 return;
143 case 0x3D5:
144 if (svga->crtcreg <= 7 && svga->crtc[0x11] & 0x80) return;
145 if (svga->crtcreg >= 0x20 && svga->crtcreg != 0x38 && (svga->crtc[0x38] & 0xcc) != 0x48) return;
146 old = svga->crtc[svga->crtcreg];
147 svga->crtc[svga->crtcreg] = val;
148 switch (svga->crtcreg)
149 {
150 case 0x31:
151 s3->ma_ext = (s3->ma_ext & 0x1c) | ((val & 0x30) >> 4);
152 svga->vrammask = /*(val & 8) ? */s3->vram_mask/* : 0x3ffff*/;
153 break;
155 case 0x50:
156 switch (svga->crtc[0x50] & 0xc1)
157 {
158 case 0x00: s3->width = (svga->crtc[0x31] & 2) ? 2048 : 1024; break;
159 case 0x01: s3->width = 1152; break;
160 case 0x40: s3->width = 640; break;
161 case 0x80: s3->width = 800; break;
162 case 0x81: s3->width = 1600; break;
163 case 0xc0: s3->width = 1280; break;
164 }
165 s3->bpp = (svga->crtc[0x50] >> 4) & 3;
166 break;
167 case 0x69:
168 s3->ma_ext = val & 0x1f;
169 break;
171 case 0x35:
172 s3->bank = (s3->bank & 0x70) | (val & 0xf);
173 // pclog("CRTC write R35 %02X\n", val);
174 if (svga->chain4) svga->write_bank = svga->read_bank = s3->bank << 16;
175 else svga->write_bank = svga->read_bank = s3->bank << 14;
176 break;
177 case 0x51:
178 s3->bank = (s3->bank & 0x4f) | ((val & 0xc) << 2);
179 // pclog("CRTC write R51 %02X\n", val);
180 if (svga->chain4) svga->write_bank = svga->read_bank = s3->bank << 16;
181 else svga->write_bank = svga->read_bank = s3->bank << 14;
182 s3->ma_ext = (s3->ma_ext & ~0xc) | ((val & 3) << 2);
183 break;
184 case 0x6a:
185 s3->bank = val;
186 // pclog("CRTC write R6a %02X\n", val);
187 if (svga->chain4) svga->write_bank = svga->read_bank = s3->bank << 16;
188 else svga->write_bank = svga->read_bank = s3->bank << 14;
189 break;
191 case 0x3a:
192 if (val & 0x10)
193 svga->gdcreg[5] |= 0x40; /*Horrible cheat*/
194 break;
196 case 0x45:
197 svga->hwcursor.ena = val & 1;
198 break;
199 case 0x48:
200 svga->hwcursor.x = ((svga->crtc[0x46] << 8) | svga->crtc[0x47]) & 0x7ff;
201 if (svga->bpp == 32) svga->hwcursor.x >>= 1;
202 svga->hwcursor.y = ((svga->crtc[0x48] << 8) | svga->crtc[0x49]) & 0x7ff;
203 svga->hwcursor.xoff = svga->crtc[0x4e] & 63;
204 svga->hwcursor.yoff = svga->crtc[0x4f] & 63;
205 svga->hwcursor.addr = ((((svga->crtc[0x4c] << 8) | svga->crtc[0x4d]) & 0xfff) * 1024) + (svga->hwcursor.yoff * 16);
206 if ((s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) && svga->bpp == 32)
207 svga->hwcursor.x <<= 1;
208 break;
210 case 0x53:
211 case 0x58: case 0x59: case 0x5a:
212 s3_updatemapping(s3);
213 break;
215 case 0x67:
216 if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64)
217 {
218 switch (val >> 4)
219 {
220 case 3: svga->bpp = 15; break;
221 case 5: svga->bpp = 16; break;
222 case 7: svga->bpp = 24; break;
223 case 13: svga->bpp = 32; break;
224 default: svga->bpp = 8; break;
225 }
226 }
227 break;
228 //case 0x55: case 0x43:
229 // pclog("Write CRTC R%02X %02X\n", crtcreg, val);
230 }
231 if (old != val)
232 {
233 if (svga->crtcreg < 0xe || svga->crtcreg > 0x10)
234 {
235 svga->fullchange = changeframecount;
236 svga_recalctimings(svga);
237 }
238 }
239 break;
240 }
241 svga_out(addr, val, svga);
242 }
244 uint8_t s3_in(uint16_t addr, void *p)
245 {
246 s3_t *s3 = (s3_t *)p;
247 svga_t *svga = &s3->svga;
249 if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1))
250 addr ^= 0x60;
252 // if (addr != 0x3da) pclog("S3 in %04X %08x:%02x\n", addr, CS, pc);
253 switch (addr)
254 {
255 case 0x3c5:
256 if (svga->seqaddr >= 0x10 && svga->seqaddr < 0x20)
257 return svga->seqregs[svga->seqaddr];
258 break;
260 case 0x3c6: case 0x3c7: case 0x3c8: case 0x3c9:
261 // pclog("Read RAMDAC %04X %04X:%04X\n", addr, CS, pc);
262 return sdac_ramdac_in(addr, &s3->ramdac, svga);
264 case 0x3d4:
265 return svga->crtcreg;
266 case 0x3d5:
267 // pclog("Read CRTC R%02X %02x %04X:%04X\n", svga->crtcreg, svga->crtc[svga->crtcreg], CS, pc);
268 switch (svga->crtcreg)
269 {
270 case 0x2d: return 0x88; /*Extended chip ID*/
271 case 0x2e: return s3->id_ext; /*New chip ID*/
272 case 0x2f: return 0; /*Revision level*/
273 case 0x30: return s3->id; /*Chip ID*/
274 case 0x31: return (svga->crtc[0x31] & 0xcf) | ((s3->ma_ext & 3) << 4);
275 case 0x35: return (svga->crtc[0x35] & 0xf0) | (s3->bank & 0xf);
276 case 0x51: return (svga->crtc[0x51] & 0xf0) | ((s3->bank >> 2) & 0xc) | ((s3->ma_ext >> 2) & 3);
277 case 0x69: return s3->ma_ext;
278 case 0x6a: return s3->bank;
279 }
280 return svga->crtc[svga->crtcreg];
281 }
282 return svga_in(addr, svga);
283 }
285 void s3_recalctimings(svga_t *svga)
286 {
287 s3_t *s3 = (s3_t *)svga->p;
288 svga->hdisp = svga->hdisp_old;
290 // pclog("%i %i\n", svga->hdisp, svga->hdisp_time);
291 // pclog("recalctimings\n");
292 svga->ma_latch |= (s3->ma_ext << 16);
293 // pclog("SVGA_MA %08X\n", svga_ma);
294 if (svga->crtc[0x5d] & 0x01) svga->htotal += 0x100;
295 if (svga->crtc[0x5d] & 0x02)
296 {
297 svga->hdisp_time += 0x100;
298 svga->hdisp += 0x100 * ((svga->seqregs[1] & 8) ? 16 : 8);
299 }
300 if (svga->crtc[0x5e] & 0x01) svga->vtotal += 0x400;
301 if (svga->crtc[0x5e] & 0x02) svga->dispend += 0x400;
302 if (svga->crtc[0x5e] & 0x04) svga->vblankstart += 0x400;
303 if (svga->crtc[0x5e] & 0x10) svga->vsyncstart += 0x400;
304 if (svga->crtc[0x5e] & 0x40) svga->split += 0x400;
305 if (svga->crtc[0x51] & 0x30) svga->rowoffset += (svga->crtc[0x51] & 0x30) << 4;
306 else if (svga->crtc[0x43] & 0x04) svga->rowoffset += 0x100;
307 if (!svga->rowoffset) svga->rowoffset = 256;
308 svga->interlace = svga->crtc[0x42] & 0x20;
309 svga->clock = cpuclock / s3->getclock((svga->miscout >> 2) & 3, s3->getclock_p);
311 switch (svga->crtc[0x67] >> 4)
312 {
313 case 3: case 5: case 7:
314 svga->clock /= 2;
315 break;
316 }
318 svga->lowres = !((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10));
319 if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10))
320 {
321 switch (svga->bpp)
322 {
323 case 8:
324 svga->render = svga_render_8bpp_highres;
325 break;
326 case 15:
327 svga->render = svga_render_15bpp_highres;
328 svga->hdisp /= 2;
329 break;
330 case 16:
331 svga->render = svga_render_16bpp_highres;
332 svga->hdisp /= 2;
333 break;
334 case 24:
335 svga->render = svga_render_24bpp_highres;
336 svga->hdisp /= 3;
337 break;
338 case 32:
339 svga->render = svga_render_32bpp_highres;
340 if (s3->chip != S3_TRIO32 && s3->chip != S3_TRIO64)
341 svga->hdisp /= 4;
342 break;
343 }
344 }
345 }
347 void s3_updatemapping(s3_t *s3)
348 {
349 svga_t *svga = &s3->svga;
351 // video_write_a000_w = video_write_a000_l = NULL;
353 if (!(s3->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM))
354 {
355 // pclog("Update mapping - PCI disabled\n");
356 mem_mapping_disable(&svga->mapping);
357 mem_mapping_disable(&s3->linear_mapping);
358 mem_mapping_disable(&s3->mmio_mapping);
359 return;
360 }
362 // pclog("Update mapping - bank %02X ", svga->gdcreg[6] & 0xc);
363 switch (svga->gdcreg[6] & 0xc) /*Banked framebuffer*/
364 {
365 case 0x0: /*128k at A0000*/
366 mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000);
367 svga->banked_mask = 0xffff;
368 break;
369 case 0x4: /*64k at A0000*/
370 mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000);
371 svga->banked_mask = 0xffff;
372 break;
373 case 0x8: /*32k at B0000*/
374 mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000);
375 svga->banked_mask = 0x7fff;
376 break;
377 case 0xC: /*32k at B8000*/
378 mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000);
379 svga->banked_mask = 0x7fff;
380 break;
381 }
383 // pclog("Linear framebuffer %02X ", svga->crtc[0x58] & 0x10);
384 if (svga->crtc[0x58] & 0x10) /*Linear framebuffer*/
385 {
386 mem_mapping_disable(&svga->mapping);
388 s3->linear_base = (svga->crtc[0x5a] << 16) | (svga->crtc[0x59] << 24);
389 switch (svga->crtc[0x58] & 3)
390 {
391 case 0: /*64k*/
392 s3->linear_size = 0x10000;
393 break;
394 case 1: /*1mb*/
395 s3->linear_size = 0x100000;
396 break;
397 case 2: /*2mb*/
398 s3->linear_size = 0x200000;
399 break;
400 case 3: /*8mb*/
401 s3->linear_size = 0x800000;
402 break;
403 }
404 s3->linear_base &= ~(s3->linear_size - 1);
405 // pclog("%08X %08X %02X %02X %02X\n", linear_base, linear_size, crtc[0x58], crtc[0x59], crtc[0x5a]);
406 // pclog("Linear framebuffer at %08X size %08X\n", s3->linear_base, s3->linear_size);
407 if (s3->linear_base == 0xa0000)
408 {
409 mem_mapping_disable(&s3->linear_mapping);
410 if (!(svga->crtc[0x53] & 0x10))
411 {
412 mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000);
413 svga->banked_mask = 0xffff;
414 }
415 // mem_mapping_set_addr(&s3->linear_mapping, 0xa0000, 0x10000);
416 }
417 else
418 mem_mapping_set_addr(&s3->linear_mapping, s3->linear_base, s3->linear_size);
419 }
420 else
421 mem_mapping_disable(&s3->linear_mapping);
423 // pclog("Memory mapped IO %02X\n", svga->crtc[0x53] & 0x10);
424 if (svga->crtc[0x53] & 0x10) /*Memory mapped IO*/
425 {
426 mem_mapping_disable(&svga->mapping);
427 mem_mapping_enable(&s3->mmio_mapping);
428 }
429 else
430 mem_mapping_disable(&s3->mmio_mapping);
431 }
433 static float s3_trio64_getclock(int clock, void *p)
434 {
435 s3_t *s3 = (s3_t *)p;
436 svga_t *svga = &s3->svga;
437 float t;
438 int m, n1, n2;
439 // pclog("Trio64_getclock %i %02X %02X\n", clock, svga->seqregs[0x13], svga->seqregs[0x12]);
440 if (clock == 0) return 25175000.0;
441 if (clock == 1) return 28322000.0;
442 m = svga->seqregs[0x13] + 2;
443 n1 = (svga->seqregs[0x12] & 0x1f) + 2;
444 n2 = ((svga->seqregs[0x12] >> 5) & 0x07);
445 t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2);
446 // pclog("TRIO64 clock %i %i %i %f %f %i\n", m, n1, n2, t, 14318184.0 * ((float)m / (float)n1), 1 << n2);
447 return t;
448 }
451 void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3);
453 void s3_accel_out(uint16_t port, uint8_t val, void *p)
454 {
455 s3_t *s3 = (s3_t *)p;
456 // pclog("Accel out %04X %02X\n", port, val);
458 switch (port)
459 {
460 case 0x42e8:
461 break;
462 case 0x42e9:
463 s3->accel.subsys_cntl = val;
464 break;
465 case 0x46e8:
466 s3->accel.setup_md = val;
467 break;
468 case 0x4ae8:
469 s3->accel.advfunc_cntl = val;
470 break;
472 case 0x82e8:
473 s3->accel.cur_y = (s3->accel.cur_y & 0xf00) | val;
474 break;
475 case 0x82e9:
476 s3->accel.cur_y = (s3->accel.cur_y & 0xff) | ((val & 0x1f) << 8);
477 break;
479 case 0x86e8:
480 s3->accel.cur_x = (s3->accel.cur_x & 0xf00) | val;
481 break;
482 case 0x86e9:
483 s3->accel.cur_x = (s3->accel.cur_x & 0xff) | ((val & 0x1f) << 8);
484 break;
486 case 0x8ae8:
487 s3->accel.desty_axstp = (s3->accel.desty_axstp & 0x3f00) | val;
488 break;
489 case 0x8ae9:
490 s3->accel.desty_axstp = (s3->accel.desty_axstp & 0xff) | ((val & 0x3f) << 8);
491 if (val & 0x20)
492 s3->accel.desty_axstp |= ~0x3fff;
493 break;
495 case 0x8ee8:
496 s3->accel.destx_distp = (s3->accel.destx_distp & 0x3f00) | val;
497 break;
498 case 0x8ee9:
499 s3->accel.destx_distp = (s3->accel.destx_distp & 0xff) | ((val & 0x3f) << 8);
500 if (val & 0x20)
501 s3->accel.destx_distp |= ~0x3fff;
502 break;
504 case 0x92e8:
505 s3->accel.err_term = (s3->accel.err_term & 0x3f00) | val;
506 break;
507 case 0x92e9:
508 s3->accel.err_term = (s3->accel.err_term & 0xff) | ((val & 0x3f) << 8);
509 if (val & 0x20)
510 s3->accel.err_term |= ~0x3fff;
511 break;
513 case 0x96e8:
514 s3->accel.maj_axis_pcnt = (s3->accel.maj_axis_pcnt & 0x3f00) | val;
515 break;
516 case 0x96e9:
517 s3->accel.maj_axis_pcnt = (s3->accel.maj_axis_pcnt & 0xff) | ((val & 0x0f) << 8);
518 if (val & 0x08)
519 s3->accel.maj_axis_pcnt |= ~0x0fff;
520 break;
522 case 0x9ae8:
523 s3->accel.cmd = (s3->accel.cmd & 0xff00) | val;
524 break;
525 case 0x9ae9:
526 s3->accel.cmd = (s3->accel.cmd & 0xff) | (val << 8);
527 s3_accel_start(-1, 0, 0xffffffff, 0, s3);
528 s3->accel.pix_trans_count = 0;
529 s3->accel.multifunc[0xe] &= ~0x10; /*hack*/
530 break;
532 case 0x9ee8:
533 s3->accel.short_stroke = (s3->accel.short_stroke & 0xff00) | val;
534 break;
535 case 0x9ee9:
536 s3->accel.short_stroke = (s3->accel.short_stroke & 0xff) | (val << 8);
537 break;
539 case 0xa2e8:
540 if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200))
541 s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16);
542 else
543 s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x000000ff) | val;
544 break;
545 case 0xa2e9:
546 if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200))
547 s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0xff000000) | (val << 24);
548 else
549 s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x0000ff00) | (val << 8);
550 if (!(s3->accel.multifunc[0xe] & 0x200))
551 s3->accel.multifunc[0xe] ^= 0x10;
552 break;
553 case 0xa2ea:
554 if (s3->accel.multifunc[0xe] & 0x200)
555 s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16);
556 break;
557 case 0xa2eb:
558 if (s3->accel.multifunc[0xe] & 0x200)
559 s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0xff000000) | (val << 24);
560 break;
562 case 0xa6e8:
563 if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200))
564 s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16);
565 else
566 s3->accel.frgd_color = (s3->accel.frgd_color & ~0x000000ff) | val;
567 break;
568 case 0xa6e9:
569 if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200))
570 s3->accel.frgd_color = (s3->accel.frgd_color & ~0xff000000) | (val << 24);
571 else
572 s3->accel.frgd_color = (s3->accel.frgd_color & ~0x0000ff00) | (val << 8);
573 if (!(s3->accel.multifunc[0xe] & 0x200))
574 s3->accel.multifunc[0xe] ^= 0x10;
575 break;
576 case 0xa6ea:
577 if (s3->accel.multifunc[0xe] & 0x200)
578 s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16);
579 break;
580 case 0xa6eb:
581 if (s3->accel.multifunc[0xe] & 0x200)
582 s3->accel.frgd_color = (s3->accel.frgd_color & ~0xff000000) | (val << 24);
583 break;
585 case 0xaae8:
586 if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200))
587 s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16);
588 else
589 s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x000000ff) | val;
590 break;
591 case 0xaae9:
592 if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200))
593 s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0xff000000) | (val << 24);
594 else
595 s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x0000ff00) | (val << 8);
596 if (!(s3->accel.multifunc[0xe] & 0x200))
597 s3->accel.multifunc[0xe] ^= 0x10;
598 break;
599 case 0xaaea:
600 if (s3->accel.multifunc[0xe] & 0x200)
601 s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16);
602 break;
603 case 0xaaeb:
604 if (s3->accel.multifunc[0xe] & 0x200)
605 s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0xff000000) | (val << 24);
606 break;
608 case 0xaee8:
609 if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200))
610 s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16);
611 else
612 s3->accel.rd_mask = (s3->accel.rd_mask & ~0x000000ff) | val;
613 break;
614 case 0xaee9:
615 if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200))
616 s3->accel.rd_mask = (s3->accel.rd_mask & ~0xff000000) | (val << 24);
617 else
618 s3->accel.rd_mask = (s3->accel.rd_mask & ~0x0000ff00) | (val << 8);
619 if (!(s3->accel.multifunc[0xe] & 0x200))
620 s3->accel.multifunc[0xe] ^= 0x10;
621 break;
622 case 0xaeea:
623 if (s3->accel.multifunc[0xe] & 0x200)
624 s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16);
625 break;
626 case 0xaeeb:
627 if (s3->accel.multifunc[0xe] & 0x200)
628 s3->accel.rd_mask = (s3->accel.rd_mask & ~0xff000000) | (val << 24);
629 break;
631 case 0xb2e8:
632 if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200))
633 s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16);
634 else
635 s3->accel.color_cmp = (s3->accel.color_cmp & ~0x000000ff) | val;
636 break;
637 case 0xb2e9:
638 if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200))
639 s3->accel.color_cmp = (s3->accel.color_cmp & ~0xff000000) | (val << 24);
640 else
641 s3->accel.color_cmp = (s3->accel.color_cmp & ~0x0000ff00) | (val << 8);
642 if (!(s3->accel.multifunc[0xe] & 0x200))
643 s3->accel.multifunc[0xe] ^= 0x10;
644 break;
645 case 0xb2ea:
646 if (s3->accel.multifunc[0xe] & 0x200)
647 s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16);
648 break;
649 case 0xb2eb:
650 if (s3->accel.multifunc[0xe] & 0x200)
651 s3->accel.color_cmp = (s3->accel.color_cmp & ~0xff000000) | (val << 24);
652 break;
654 case 0xb6e8:
655 s3->accel.bkgd_mix = val;
656 break;
658 case 0xbae8:
659 s3->accel.frgd_mix = val;
660 break;
662 case 0xbee8:
663 s3->accel.multifunc_cntl = (s3->accel.multifunc_cntl & 0xff00) | val;
664 break;
665 case 0xbee9:
666 s3->accel.multifunc_cntl = (s3->accel.multifunc_cntl & 0xff) | (val << 8);
667 s3->accel.multifunc[s3->accel.multifunc_cntl >> 12] = s3->accel.multifunc_cntl & 0xfff;
668 break;
670 case 0xe2e8:
671 s3->accel.pix_trans[0] = val;
672 if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100))
673 s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3);
674 else if (!(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100))
675 s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0], s3);
676 break;
677 case 0xe2e9:
678 s3->accel.pix_trans[1] = val;
679 if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x600) == 0x200 && (s3->accel.cmd & 0x100))
680 {
681 if (s3->accel.cmd & 0x1000) s3_accel_start(16, 1, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), 0, s3);
682 else s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3);
683 }
684 else if ((s3->accel.cmd & 0x600) == 0x200 && (s3->accel.cmd & 0x100))
685 {
686 if (s3->accel.cmd & 0x1000) s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3);
687 else s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3);
688 }
689 break;
690 case 0xe2ea:
691 s3->accel.pix_trans[2] = val;
692 break;
693 case 0xe2eb:
694 s3->accel.pix_trans[3] = val;
695 if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x600) == 0x400 && (s3->accel.cmd & 0x100))
696 s3_accel_start(32, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), 0, s3);
697 else if ((s3->accel.cmd & 0x600) == 0x400 && (s3->accel.cmd & 0x100))
698 s3_accel_start(4, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3);
699 break;
700 }
701 }
703 void s3_accel_out_w(uint16_t port, uint16_t val, void *p)
704 {
705 s3_t *s3 = (s3_t *)p;
706 // pclog("Accel out w %04X %04X\n", port, val);
707 if (s3->accel.cmd & 0x100)
708 {
709 if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80)
710 {
711 if (s3->accel.cmd & 0x1000)
712 val = (val >> 8) | (val << 8);
713 s3_accel_start(16, 1, val | (val << 16), 0, s3);
714 }
715 else
716 s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3);
717 }
718 }
720 void s3_accel_out_l(uint16_t port, uint32_t val, void *p)
721 {
722 s3_t *s3 = (s3_t *)p;
723 // pclog("Accel out l %04X %08X\n", port, val);
724 if (s3->accel.cmd & 0x100)
725 {
726 if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80)
727 {
728 if (s3->accel.cmd & 0x1000)
729 val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24);
730 if ((s3->accel.cmd & 0x600) == 0x400)
731 s3_accel_start(32, 1, val, 0, s3);
732 else if ((s3->accel.cmd & 0x600) == 0x200)
733 {
734 s3_accel_start(16, 1, val >> 16, 0, s3);
735 s3_accel_start(16, 1, val, 0, s3);
736 }
737 else if (!(s3->accel.cmd & 0x600))
738 {
739 s3_accel_start(8, 1, val >> 24, 0, s3);
740 s3_accel_start(8, 1, val >> 16, 0, s3);
741 s3_accel_start(8, 1, val >> 8, 0, s3);
742 s3_accel_start(8, 1, val, 0, s3);
743 }
744 }
745 else
746 {
747 if ((s3->accel.cmd & 0x600) == 0x400)
748 s3_accel_start(4, 1, 0xffffffff, val, s3);
749 else if ((s3->accel.cmd & 0x600) == 0x200)
750 {
751 s3_accel_start(2, 1, 0xffffffff, val >> 16, s3);
752 s3_accel_start(2, 1, 0xffffffff, val, s3);
753 }
754 else if (!(s3->accel.cmd & 0x600))
755 {
756 s3_accel_start(1, 1, 0xffffffff, val >> 24, s3);
757 s3_accel_start(1, 1, 0xffffffff, val >> 16, s3);
758 s3_accel_start(1, 1, 0xffffffff, val >> 8, s3);
759 s3_accel_start(1, 1, 0xffffffff, val, s3);
760 }
761 }
762 }
763 }
765 uint8_t s3_accel_in(uint16_t port, void *p)
766 {
767 s3_t *s3 = (s3_t *)p;
768 int temp;
769 // pclog("Accel in %04X\n", port);
770 switch (port)
771 {
772 case 0x42e8:
773 return 0;
774 case 0x42e9:
775 return 0;
777 case 0x82e8:
778 return s3->accel.cur_y & 0xff;
779 case 0x82e9:
780 return s3->accel.cur_y >> 8;
782 case 0x86e8:
783 return s3->accel.cur_x & 0xff;
784 case 0x86e9:
785 return s3->accel.cur_x >> 8;
787 case 0x8ae8:
788 return s3->accel.desty_axstp & 0xff;
789 case 0x8ae9:
790 return s3->accel.desty_axstp >> 8;
792 case 0x8ee8:
793 return s3->accel.destx_distp & 0xff;
794 case 0x8ee9:
795 return s3->accel.destx_distp >> 8;
797 case 0x92e8:
798 return s3->accel.err_term & 0xff;
799 case 0x92e9:
800 return s3->accel.err_term >> 8;
802 case 0x96e8:
803 return s3->accel.maj_axis_pcnt & 0xff;
804 case 0x96e9:
805 return s3->accel.maj_axis_pcnt >> 8;
807 case 0x9ae8:
808 return 0; /*FIFO empty*/
809 case 0x9ae9:
810 return 0x04; /*FIFO empty*/
812 case 0xa2e8:
813 return s3->accel.bkgd_color & 0xff;
814 case 0xa2e9:
815 return s3->accel.bkgd_color >> 8;
816 case 0xa2ea:
817 return s3->accel.bkgd_color >> 16;
818 case 0xa2eb:
819 return s3->accel.bkgd_color >> 24;
821 case 0xa6e8:
822 return s3->accel.frgd_color & 0xff;
823 case 0xa6e9:
824 return s3->accel.frgd_color >> 8;
825 case 0xa6ea:
826 return s3->accel.frgd_color >> 16;
827 case 0xa6eb:
828 return s3->accel.frgd_color >> 24;
830 case 0xaae8:
831 return s3->accel.wrt_mask & 0xff;
832 case 0xaae9:
833 return s3->accel.wrt_mask >> 8;
834 case 0xaaea:
835 return s3->accel.wrt_mask >> 16;
836 case 0xaaeb:
837 return s3->accel.wrt_mask >> 24;
839 case 0xaee8:
840 return s3->accel.rd_mask & 0xff;
841 case 0xaee9:
842 return s3->accel.rd_mask >> 8;
843 case 0xaeea:
844 return s3->accel.rd_mask >> 16;
845 case 0xaeeb:
846 return s3->accel.rd_mask >> 24;
848 case 0xb2e8:
849 return s3->accel.color_cmp & 0xff;
850 case 0xb2e9:
851 return s3->accel.color_cmp >> 8;
852 case 0xb2ea:
853 return s3->accel.color_cmp >> 16;
854 case 0xb2eb:
855 return s3->accel.color_cmp >> 24;
857 case 0xb6e8:
858 return s3->accel.bkgd_mix;
860 case 0xbae8:
861 return s3->accel.frgd_mix;
863 case 0xbee8:
864 temp = s3->accel.multifunc[0xf] & 0xf;
865 switch (temp)
866 {
867 case 0x0: return s3->accel.multifunc[0x0] & 0xff;
868 case 0x1: return s3->accel.multifunc[0x1] & 0xff;
869 case 0x2: return s3->accel.multifunc[0x2] & 0xff;
870 case 0x3: return s3->accel.multifunc[0x3] & 0xff;
871 case 0x4: return s3->accel.multifunc[0x4] & 0xff;
872 case 0x5: return s3->accel.multifunc[0xa] & 0xff;
873 case 0x6: return s3->accel.multifunc[0xe] & 0xff;
874 case 0x7: return s3->accel.cmd & 0xff;
875 case 0x8: return s3->accel.subsys_cntl & 0xff;
876 case 0x9: return s3->accel.setup_md & 0xff;
877 case 0xa: return s3->accel.multifunc[0xd] & 0xff;
878 }
879 return 0xff;
880 case 0xbee9:
881 temp = s3->accel.multifunc[0xf] & 0xf;
882 s3->accel.multifunc[0xf]++;
883 switch (temp)
884 {
885 case 0x0: return s3->accel.multifunc[0x0] >> 8;
886 case 0x1: return s3->accel.multifunc[0x1] >> 8;
887 case 0x2: return s3->accel.multifunc[0x2] >> 8;
888 case 0x3: return s3->accel.multifunc[0x3] >> 8;
889 case 0x4: return s3->accel.multifunc[0x4] >> 8;
890 case 0x5: return s3->accel.multifunc[0xa] >> 8;
891 case 0x6: return s3->accel.multifunc[0xe] >> 8;
892 case 0x7: return s3->accel.cmd >> 8;
893 case 0x8: return (s3->accel.subsys_cntl >> 8) & ~0xe000;
894 case 0x9: return (s3->accel.setup_md >> 8) & ~0xf000;
895 case 0xa: return s3->accel.multifunc[0xd] >> 8;
896 }
897 return 0xff;
899 case 0xe2e8: case 0xe2e9: case 0xe2ea: case 0xe2eb: /*PIX_TRANS*/
900 break;
901 }
902 return 0;
903 }
905 #define WRITE8(addr, var, val) switch ((addr) & 3) \
906 { \
907 case 0: var = (var & 0xffffff00) | (val); break; \
908 case 1: var = (var & 0xffff00ff) | ((val) << 8); break; \
909 case 2: var = (var & 0xff00ffff) | ((val) << 16); break; \
910 case 3: var = (var & 0x00ffffff) | ((val) << 24); break; \
911 }
913 void s3_accel_write(uint32_t addr, uint8_t val, void *p)
914 {
915 s3_t *s3 = (s3_t *)p;
916 // pclog("Write S3 accel %08X %02X\n", addr, val);
917 if (s3->packed_mmio)
918 {
919 int addr_lo = addr & 1;
920 switch (addr & 0xfffe)
921 {
922 case 0x8100: addr = 0x82e8; break; /*ALT_CURXY*/
923 case 0x8102: addr = 0x86e8; break;
925 case 0x8104: addr = 0x82ea; break; /*ALT_CURXY2*/
926 case 0x8106: addr = 0x86ea; break;
928 case 0x8108: addr = 0x8ae8; break; /*ALT_STEP*/
929 case 0x810a: addr = 0x8ee8; break;
931 case 0x810c: addr = 0x8aea; break; /*ALT_STEP2*/
932 case 0x810e: addr = 0x8eea; break;
934 case 0x8110: addr = 0x92e8; break; /*ALT_ERR*/
935 case 0x8112: addr = 0x92ee; break;
937 case 0x8118: addr = 0x9ae8; break; /*ALT_CMD*/
938 case 0x811a: addr = 0x9aea; break;
940 case 0x811c: addr = 0x9ee8; break; /*SHORT_STROKE*/
942 case 0x8120: case 0x8122: /*BKGD_COLOR*/
943 WRITE8(addr, s3->accel.bkgd_color, val);
944 return;
946 case 0x8124: case 0x8126: /*FRGD_COLOR*/
947 WRITE8(addr, s3->accel.frgd_color, val);
948 return;
950 case 0x8128: case 0x812a: /*WRT_MASK*/
951 WRITE8(addr, s3->accel.wrt_mask, val);
952 return;
954 case 0x812c: case 0x812e: /*RD_MASK*/
955 WRITE8(addr, s3->accel.rd_mask, val);
956 return;
958 case 0x8130: case 0x8132: /*COLOR_CMP*/
959 WRITE8(addr, s3->accel.color_cmp, val);
960 return;
962 case 0x8134: addr = 0xb6e8; break; /*ALT_MIX*/
963 case 0x8136: addr = 0xbae8; break;
965 case 0x8138: /*SCISSORS_T*/
966 WRITE8(addr & 1, s3->accel.multifunc[1], val);
967 return;
968 case 0x813a: /*SCISSORS_L*/
969 WRITE8(addr & 1, s3->accel.multifunc[2], val);
970 return;
971 case 0x813c: /*SCISSORS_B*/
972 WRITE8(addr & 1, s3->accel.multifunc[3], val);
973 return;
974 case 0x813e: /*SCISSORS_R*/
975 WRITE8(addr & 1, s3->accel.multifunc[4], val);
976 return;
978 case 0x8140: /*PIX_CNTL*/
979 WRITE8(addr & 1, s3->accel.multifunc[0xa], val);
980 return;
981 case 0x8142: /*MULT_MISC2*/
982 WRITE8(addr & 1, s3->accel.multifunc[0xd], val);
983 return;
984 case 0x8144: /*MULT_MISC*/
985 WRITE8(addr & 1, s3->accel.multifunc[0xe], val);
986 return;
987 case 0x8146: /*READ_SEL*/
988 WRITE8(addr & 1, s3->accel.multifunc[0xf], val);
989 return;
991 case 0x8148: /*ALT_PCNT*/
992 WRITE8(addr & 1, s3->accel.multifunc[0], val);
993 return;
994 case 0x814a: addr = 0x96e8; break;
995 case 0x814c: addr = 0x96ea; break;
997 case 0x8168: addr = 0xeae8; break;
998 case 0x816a: addr = 0xeaea; break;
999 }
1000 addr |= addr_lo;
1004 if (addr & 0x8000)
1006 s3_accel_out(addr & 0xffff, val, p);
1008 else
1010 if (s3->accel.cmd & 0x100)
1012 if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80)
1013 s3_accel_start(8, 1, val | (val << 8) | (val << 16) | (val << 24), 0, s3);
1014 else
1015 s3_accel_start(1, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3);
1020 void s3_accel_write_w(uint32_t addr, uint16_t val, void *p)
1022 s3_t *s3 = (s3_t *)p;
1023 // pclog("Write S3 accel w %08X %04X\n", addr, val);
1024 if (addr & 0x8000)
1026 s3_accel_write(addr, val, p);
1027 s3_accel_write(addr + 1, val >> 8, p);
1029 else
1031 if (s3->accel.cmd & 0x100)
1033 if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80)
1035 if (s3->accel.cmd & 0x1000)
1036 val = (val >> 8) | (val << 8);
1037 s3_accel_start(16, 1, val | (val << 16), 0, s3);
1039 else
1040 s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3);
1045 void s3_accel_write_l(uint32_t addr, uint32_t val, void *p)
1047 s3_t *s3 = (s3_t *)p;
1048 // pclog("Write S3 accel l %08X %08X\n", addr, val);
1049 if (addr & 0x8000)
1051 s3_accel_write(addr, val, p);
1052 s3_accel_write(addr + 1, val >> 8, p);
1053 s3_accel_write(addr + 2, val >> 16, p);
1054 s3_accel_write(addr + 3, val >> 24, p);
1056 else
1058 if (s3->accel.cmd & 0x100)
1060 if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80)
1062 if (s3->accel.cmd & 0x1000)
1063 val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24);
1064 if ((s3->accel.cmd & 0x600) == 0x400)
1065 s3_accel_start(32, 1, val, 0, s3);
1066 else if ((s3->accel.cmd & 0x600) == 0x200)
1068 s3_accel_start(16, 1, val >> 16, 0, s3);
1069 s3_accel_start(16, 1, val, 0, s3);
1071 else if (!(s3->accel.cmd & 0x600))
1073 s3_accel_start(8, 1, val >> 24, 0, s3);
1074 s3_accel_start(8, 1, val >> 16, 0, s3);
1075 s3_accel_start(8, 1, val >> 8, 0, s3);
1076 s3_accel_start(8, 1, val, 0, s3);
1079 else
1081 if ((s3->accel.cmd & 0x600) == 0x400)
1082 s3_accel_start(4, 1, 0xffffffff, val, s3);
1083 else if ((s3->accel.cmd & 0x600) == 0x200)
1085 s3_accel_start(2, 1, 0xffffffff, val, s3);
1086 s3_accel_start(2, 1, 0xffffffff, val >> 16, s3);
1088 else if (!(s3->accel.cmd & 0x600))
1090 s3_accel_start(1, 1, 0xffffffff, val, s3);
1091 s3_accel_start(1, 1, 0xffffffff, val >> 8, s3);
1092 s3_accel_start(1, 1, 0xffffffff, val >> 16, s3);
1093 s3_accel_start(1, 1, 0xffffffff, val >> 24, s3);
1100 uint8_t s3_accel_read(uint32_t addr, void *p)
1102 if (addr & 0x8000)
1103 return s3_accel_in(addr & 0xffff, p);
1104 return 0;
1107 #define READ(addr, dat) if (s3->bpp == 0) dat = svga->vram[ (addr) & s3->vram_mask]; \
1108 else if (s3->bpp == 1) dat = vram_w[(addr) & (s3->vram_mask >> 1)]; \
1109 else dat = vram_l[(addr) & (s3->vram_mask >> 2)];
1111 #define MIX switch ((mix_dat & mix_mask) ? (s3->accel.frgd_mix & 0xf) : (s3->accel.bkgd_mix & 0xf)) \
1112 { \
1113 case 0x0: dest_dat = ~dest_dat; break; \
1114 case 0x1: dest_dat = 0; break; \
1115 case 0x2: dest_dat = ~0; break; \
1116 case 0x3: dest_dat = dest_dat; break; \
1117 case 0x4: dest_dat = ~src_dat; break; \
1118 case 0x5: dest_dat = src_dat ^ dest_dat; break; \
1119 case 0x6: dest_dat = ~(src_dat ^ dest_dat); break; \
1120 case 0x7: dest_dat = src_dat; break; \
1121 case 0x8: dest_dat = ~(src_dat & dest_dat); break; \
1122 case 0x9: dest_dat = ~src_dat | dest_dat; break; \
1123 case 0xa: dest_dat = src_dat | ~dest_dat; break; \
1124 case 0xb: dest_dat = src_dat | dest_dat; break; \
1125 case 0xc: dest_dat = src_dat & dest_dat; break; \
1126 case 0xd: dest_dat = src_dat & ~dest_dat; break; \
1127 case 0xe: dest_dat = ~src_dat & dest_dat; break; \
1128 case 0xf: dest_dat = ~(src_dat | dest_dat); break; \
1132 #define WRITE(addr) if (s3->bpp == 0) \
1133 { \
1134 svga->vram[(addr) & s3->vram_mask] = dest_dat; \
1135 svga->changedvram[((addr) & s3->vram_mask) >> 12] = changeframecount; \
1136 } \
1137 else if (s3->bpp == 1) \
1138 { \
1139 vram_w[(addr) & (s3->vram_mask >> 1)] = dest_dat; \
1140 svga->changedvram[((addr) & (s3->vram_mask >> 1)) >> 11] = changeframecount; \
1141 } \
1142 else \
1143 { \
1144 vram_l[(addr) & (s3->vram_mask >> 2)] = dest_dat; \
1145 svga->changedvram[((addr) & (s3->vram_mask >> 2)) >> 10] = changeframecount; \
1148 void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3)
1150 svga_t *svga = &s3->svga;
1151 uint32_t src_dat, dest_dat;
1152 int frgd_mix, bkgd_mix;
1153 int clip_t = s3->accel.multifunc[1] & 0xfff;
1154 int clip_l = s3->accel.multifunc[2] & 0xfff;
1155 int clip_b = s3->accel.multifunc[3] & 0xfff;
1156 int clip_r = s3->accel.multifunc[4] & 0xfff;
1157 int vram_mask = (s3->accel.multifunc[0xa] & 0xc0) == 0xc0;
1158 uint32_t mix_mask;
1159 uint16_t *vram_w = (uint16_t *)svga->vram;
1160 uint32_t *vram_l = (uint32_t *)svga->vram;
1161 uint32_t compare = s3->accel.color_cmp;
1162 int compare_mode = (s3->accel.multifunc[0xe] >> 7) & 3;
1163 //return;
1164 // if (!cpu_input) pclog("Start S3 command %i %i, %i %i, %i (clip %i, %i to %i, %i %i)\n", s3->accel.cmd >> 13, s3->accel.cur_x, s3->accel.cur_y, s3->accel.maj_axis_pcnt & 0xfff, s3->accel.multifunc[0] & 0xfff, clip_l, clip_t, clip_r, clip_b, s3->accel.multifunc[0xe] & 0x20);
1165 // else pclog(" S3 command %i, %i, %08x %08x\n", s3->accel.cmd >> 13, count, mix_dat, cpu_dat);
1167 if (!cpu_input) s3->accel.dat_count = 0;
1168 if (cpu_input && (s3->accel.multifunc[0xa] & 0xc0) != 0x80)
1170 if (s3->bpp == 3 && count == 2)
1172 if (s3->accel.dat_count)
1174 cpu_dat = (cpu_dat & 0xffff) | (s3->accel.dat_buf << 16);
1175 count = 4;
1176 s3->accel.dat_count = 0;
1178 else
1180 s3->accel.dat_buf = cpu_dat & 0xffff;
1181 s3->accel.dat_count = 1;
1184 if (s3->bpp == 1) count >>= 1;
1185 if (s3->bpp == 3) count >>= 2;
1188 switch (s3->accel.cmd & 0x600)
1190 case 0x000: mix_mask = 0x80; break;
1191 case 0x200: mix_mask = 0x8000; break;
1192 case 0x400: mix_mask = 0x80000000; break;
1193 case 0x600: mix_mask = 0x80000000; break;
1196 if (s3->bpp == 0) compare &= 0xff;
1197 if (s3->bpp == 1) compare &= 0xffff;
1198 switch (s3->accel.cmd >> 13)
1200 case 1: /*Draw line*/
1201 if (!cpu_input) /*!cpu_input is trigger to start operation*/
1203 s3->accel.cx = s3->accel.cur_x;
1204 if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff;
1205 s3->accel.cy = s3->accel.cur_y;
1206 if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff;
1208 s3->accel.sy = s3->accel.maj_axis_pcnt;
1210 if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/
1212 frgd_mix = (s3->accel.frgd_mix >> 5) & 3;
1213 bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3;
1215 if (s3->accel.cmd & 8) /*Radial*/
1217 while (count-- && s3->accel.sy >= 0)
1219 if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r &&
1220 s3->accel.cy >= clip_t && s3->accel.cy <= clip_b)
1222 switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix)
1224 case 0: src_dat = s3->accel.bkgd_color; break;
1225 case 1: src_dat = s3->accel.frgd_color; break;
1226 case 2: src_dat = cpu_dat; break;
1227 case 3: src_dat = 0; break;
1230 if ((compare_mode == 2 && src_dat != compare) ||
1231 (compare_mode == 3 && src_dat == compare) ||
1232 compare_mode < 2)
1234 READ((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat);
1236 MIX
1238 WRITE((s3->accel.cy * s3->width) + s3->accel.cx);
1242 mix_dat <<= 1;
1243 mix_dat |= 1;
1244 if (s3->bpp == 0) cpu_dat >>= 8;
1245 else cpu_dat >>= 16;
1246 if (!s3->accel.sy)
1247 break;
1249 switch (s3->accel.cmd & 0xe0)
1251 case 0x00: s3->accel.cx++; break;
1252 case 0x20: s3->accel.cx++; s3->accel.cy--; break;
1253 case 0x40: s3->accel.cy--; break;
1254 case 0x60: s3->accel.cx--; s3->accel.cy--; break;
1255 case 0x80: s3->accel.cx--; break;
1256 case 0xa0: s3->accel.cx--; s3->accel.cy++; break;
1257 case 0xc0: s3->accel.cy++; break;
1258 case 0xe0: s3->accel.cx++; s3->accel.cy++; break;
1260 s3->accel.sy--;
1262 s3->accel.cur_x = s3->accel.cx;
1263 s3->accel.cur_y = s3->accel.cy;
1265 else /*Bresenham*/
1267 while (count-- && s3->accel.sy >= 0)
1269 if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r &&
1270 s3->accel.cy >= clip_t && s3->accel.cy <= clip_b)
1272 switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix)
1274 case 0: src_dat = s3->accel.bkgd_color; break;
1275 case 1: src_dat = s3->accel.frgd_color; break;
1276 case 2: src_dat = cpu_dat; break;
1277 case 3: src_dat = 0; break;
1280 if ((compare_mode == 2 && src_dat != compare) ||
1281 (compare_mode == 3 && src_dat == compare) ||
1282 compare_mode < 2)
1284 READ((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat);
1286 // pclog("Line : %04i, %04i (%06X) - %02X (%02X %04X %05X) %02X (%02X %02X) ", s3->accel.cx, s3->accel.cy, s3->accel.dest + s3->accel.cx, src_dat, vram[s3->accel.src + s3->accel.cx], mix_dat & mix_mask, s3->accel.src + s3->accel.cx, dest_dat, s3->accel.frgd_color, s3->accel.bkgd_color);
1288 MIX
1290 // pclog("%02X\n", dest_dat);
1292 WRITE((s3->accel.cy * s3->width) + s3->accel.cx);
1296 mix_dat <<= 1;
1297 mix_dat |= 1;
1298 if (s3->bpp == 0) cpu_dat >>= 8;
1299 else cpu_dat >>= 16;
1301 // pclog("%i, %i - %i %i %i %i\n", s3->accel.cx, s3->accel.cy, s3->accel.err_term, s3->accel.maj_axis_pcnt, s3->accel.desty_axstp, s3->accel.destx_distp);
1303 if (!s3->accel.sy)
1304 break;
1306 if (s3->accel.err_term >= s3->accel.maj_axis_pcnt)
1308 s3->accel.err_term += s3->accel.destx_distp;
1309 /*Step minor axis*/
1310 switch (s3->accel.cmd & 0xe0)
1312 case 0x00: s3->accel.cy--; break;
1313 case 0x20: s3->accel.cy--; break;
1314 case 0x40: s3->accel.cx--; break;
1315 case 0x60: s3->accel.cx++; break;
1316 case 0x80: s3->accel.cy++; break;
1317 case 0xa0: s3->accel.cy++; break;
1318 case 0xc0: s3->accel.cx--; break;
1319 case 0xe0: s3->accel.cx++; break;
1322 else
1323 s3->accel.err_term += s3->accel.desty_axstp;
1325 /*Step major axis*/
1326 switch (s3->accel.cmd & 0xe0)
1328 case 0x00: s3->accel.cx--; break;
1329 case 0x20: s3->accel.cx++; break;
1330 case 0x40: s3->accel.cy--; break;
1331 case 0x60: s3->accel.cy--; break;
1332 case 0x80: s3->accel.cx--; break;
1333 case 0xa0: s3->accel.cx++; break;
1334 case 0xc0: s3->accel.cy++; break;
1335 case 0xe0: s3->accel.cy++; break;
1337 s3->accel.sy--;
1339 s3->accel.cur_x = s3->accel.cx;
1340 s3->accel.cur_y = s3->accel.cy;
1342 break;
1344 case 2: /*Rectangle fill*/
1345 if (!cpu_input) /*!cpu_input is trigger to start operation*/
1347 s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff;
1348 s3->accel.sy = s3->accel.multifunc[0] & 0xfff;
1349 s3->accel.cx = s3->accel.cur_x;
1350 if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff;
1351 s3->accel.cy = s3->accel.cur_y;
1352 if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff;
1354 s3->accel.dest = s3->accel.cy * s3->width;
1356 // pclog("Dest %08X (%i, %i) %04X %04X\n", s3->accel.dest, s3->accel.cx, s3->accel.cy, s3->accel.cur_x, s3->accel.cur_x & 0x1000);
1358 if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/
1359 // if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !cpu_input) /*Mix data from CPU*/
1360 // return;
1362 frgd_mix = (s3->accel.frgd_mix >> 5) & 3;
1363 bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3;
1365 while (count-- && s3->accel.sy >= 0)
1367 if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r &&
1368 s3->accel.cy >= clip_t && s3->accel.cy <= clip_b)
1370 switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix)
1372 case 0: src_dat = s3->accel.bkgd_color; break;
1373 case 1: src_dat = s3->accel.frgd_color; break;
1374 case 2: src_dat = cpu_dat; break;
1375 case 3: src_dat = 0; break;
1378 if ((compare_mode == 2 && src_dat != compare) ||
1379 (compare_mode == 3 && src_dat == compare) ||
1380 compare_mode < 2)
1382 READ(s3->accel.dest + s3->accel.cx, dest_dat);
1384 // if (CS != 0xc000) pclog("Write %05X %02X %02X %04X (%02X %02X) ", s3->accel.dest + s3->accel.cx, src_dat, dest_dat, mix_dat, s3->accel.frgd_mix, s3->accel.bkgd_mix);
1386 MIX
1388 // if (CS != 0xc000) pclog("%02X\n", dest_dat);
1390 WRITE(s3->accel.dest + s3->accel.cx);
1394 mix_dat <<= 1;
1395 mix_dat |= 1;
1396 if (s3->bpp == 0) cpu_dat >>= 8;
1397 else cpu_dat >>= 16;
1399 if (s3->accel.cmd & 0x20) s3->accel.cx++;
1400 else s3->accel.cx--;
1401 s3->accel.sx--;
1402 if (s3->accel.sx < 0)
1404 if (s3->accel.cmd & 0x20) s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1;
1405 else s3->accel.cx += (s3->accel.maj_axis_pcnt & 0xfff) + 1;
1406 // s3->accel.dest -= (s3->accel.maj_axis_pcnt & 0xfff) + 1;
1407 s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff;
1409 // s3->accel.dest += s3_width;
1410 if (s3->accel.cmd & 0x80) s3->accel.cy++;
1411 else s3->accel.cy--;
1413 s3->accel.dest = s3->accel.cy * s3->width;
1414 s3->accel.sy--;
1416 if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return;
1417 if (s3->accel.sy < 0)
1419 s3->accel.cur_x = s3->accel.cx;
1420 s3->accel.cur_y = s3->accel.cy;
1421 return;
1425 break;
1427 case 6: /*BitBlt*/
1428 if (!cpu_input) /*!cpu_input is trigger to start operation*/
1430 s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff;
1431 s3->accel.sy = s3->accel.multifunc[0] & 0xfff;
1433 s3->accel.dx = s3->accel.destx_distp & 0xfff;
1434 if (s3->accel.destx_distp & 0x1000) s3->accel.dx |= ~0xfff;
1435 s3->accel.dy = s3->accel.desty_axstp & 0xfff;
1436 if (s3->accel.desty_axstp & 0x1000) s3->accel.dy |= ~0xfff;
1438 s3->accel.cx = s3->accel.cur_x & 0xfff;
1439 if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff;
1440 s3->accel.cy = s3->accel.cur_y & 0xfff;
1441 if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff;
1443 s3->accel.src = s3->accel.cy * s3->width;
1444 s3->accel.dest = s3->accel.dy * s3->width;
1446 // pclog("Source %08X Dest %08X (%i, %i) - (%i, %i)\n", s3->accel.src, s3->accel.dest, s3->accel.cx, s3->accel.cy, s3->accel.dx, s3->accel.dy);
1448 if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/
1449 // if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !cpu_input) /*Mix data from CPU*/
1450 // return;
1452 if (s3->accel.sy < 0)
1453 return;
1455 frgd_mix = (s3->accel.frgd_mix >> 5) & 3;
1456 bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3;
1458 if (!cpu_input && frgd_mix == 3 && !vram_mask && !compare_mode &&
1459 (s3->accel.cmd & 0xa0) == 0xa0 && (s3->accel.frgd_mix & 0xf) == 7)
1461 while (1)
1463 if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r &&
1464 s3->accel.dy >= clip_t && s3->accel.dy <= clip_b)
1466 READ(s3->accel.src + s3->accel.cx, src_dat);
1468 dest_dat = src_dat;
1470 WRITE(s3->accel.dest + s3->accel.dx);
1473 s3->accel.cx++;
1474 s3->accel.dx++;
1475 s3->accel.sx--;
1476 if (s3->accel.sx < 0)
1478 s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1;
1479 s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1;
1480 s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff;
1482 s3->accel.cy++;
1483 s3->accel.dy++;
1485 s3->accel.src = s3->accel.cy * s3->width;
1486 s3->accel.dest = s3->accel.dy * s3->width;
1488 s3->accel.sy--;
1490 if (s3->accel.sy < 0)
1492 s3->accel.cur_x = s3->accel.cx;
1493 s3->accel.cur_y = s3->accel.cy;
1494 return;
1499 else
1501 while (count-- && s3->accel.sy >= 0)
1503 if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r &&
1504 s3->accel.dy >= clip_t && s3->accel.dy <= clip_b)
1506 if (vram_mask)
1508 READ(s3->accel.src + s3->accel.cx, mix_dat)
1509 mix_dat = mix_dat ? mix_mask : 0;
1511 switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix)
1513 case 0: src_dat = s3->accel.bkgd_color; break;
1514 case 1: src_dat = s3->accel.frgd_color; break;
1515 case 2: src_dat = cpu_dat; break;
1516 case 3: READ(s3->accel.src + s3->accel.cx, src_dat); break;
1519 if ((compare_mode == 2 && src_dat != compare) ||
1520 (compare_mode == 3 && src_dat == compare) ||
1521 compare_mode < 2)
1523 READ(s3->accel.dest + s3->accel.dx, dest_dat);
1525 // pclog("BitBlt : %04i, %04i (%06X) - %02X (%02X %04X %05X) %02X ", s3->accel.dx, s3->accel.dy, s3->accel.dest + s3->accel.dx, src_dat, vram[s3->accel.src + s3->accel.cx], mix_dat, s3->accel.src + s3->accel.cx, dest_dat);
1527 MIX
1529 // pclog("%02X\n", dest_dat);
1531 WRITE(s3->accel.dest + s3->accel.dx);
1535 mix_dat <<= 1;
1536 mix_dat |= 1;
1537 if (s3->bpp == 0) cpu_dat >>= 8;
1538 else cpu_dat >>= 16;
1540 if (s3->accel.cmd & 0x20)
1542 s3->accel.cx++;
1543 s3->accel.dx++;
1545 else
1547 s3->accel.cx--;
1548 s3->accel.dx--;
1550 s3->accel.sx--;
1551 if (s3->accel.sx < 0)
1553 if (s3->accel.cmd & 0x20)
1555 s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1;
1556 s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1;
1558 else
1560 s3->accel.cx += (s3->accel.maj_axis_pcnt & 0xfff) + 1;
1561 s3->accel.dx += (s3->accel.maj_axis_pcnt & 0xfff) + 1;
1563 s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff;
1565 if (s3->accel.cmd & 0x80)
1567 s3->accel.cy++;
1568 s3->accel.dy++;
1570 else
1572 s3->accel.cy--;
1573 s3->accel.dy--;
1576 s3->accel.src = s3->accel.cy * s3->width;
1577 s3->accel.dest = s3->accel.dy * s3->width;
1579 s3->accel.sy--;
1581 if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return;
1582 if (s3->accel.sy < 0)
1584 s3->accel.cur_x = s3->accel.cx;
1585 s3->accel.cur_y = s3->accel.cy;
1586 return;
1591 break;
1593 case 7: /*Pattern fill - BitBlt but with source limited to 8x8*/
1594 if (!cpu_input) /*!cpu_input is trigger to start operation*/
1596 s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff;
1597 s3->accel.sy = s3->accel.multifunc[0] & 0xfff;
1599 s3->accel.dx = s3->accel.destx_distp & 0xfff;
1600 if (s3->accel.destx_distp & 0x1000) s3->accel.dx |= ~0xfff;
1601 s3->accel.dy = s3->accel.desty_axstp & 0xfff;
1602 if (s3->accel.desty_axstp & 0x1000) s3->accel.dy |= ~0xfff;
1604 s3->accel.cx = s3->accel.cur_x & 0xfff;
1605 if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff;
1606 s3->accel.cy = s3->accel.cur_y & 0xfff;
1607 if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff;
1609 /*Align source with destination*/
1610 // s3->accel.cx = (s3->accel.cx & ~7) | (s3->accel.dx & 7);
1611 // s3->accel.cy = (s3->accel.cy & ~7) | (s3->accel.dy & 7);
1613 s3->accel.pattern = (s3->accel.cy * s3->width) + s3->accel.cx;
1614 s3->accel.dest = s3->accel.dy * s3->width;
1616 s3->accel.cx = s3->accel.dx & 7;
1617 s3->accel.cy = s3->accel.dy & 7;
1619 s3->accel.src = s3->accel.pattern + (s3->accel.cy * s3->width);
1621 // pclog("Source %08X Dest %08X (%i, %i) - (%i, %i)\n", s3->accel.src, s3->accel.dest, s3->accel.cx, s3->accel.cy, s3->accel.dx, s3->accel.dy);
1622 // dumpregs();
1623 // exit(-1);
1625 if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/
1626 // if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !cpu_input) /*Mix data from CPU*/
1627 // return;
1629 frgd_mix = (s3->accel.frgd_mix >> 5) & 3;
1630 bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3;
1632 while (count-- && s3->accel.sy >= 0)
1634 if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r &&
1635 s3->accel.dy >= clip_t && s3->accel.dy <= clip_b)
1637 if (vram_mask)
1639 READ(s3->accel.src + s3->accel.cx, mix_dat)
1640 mix_dat = mix_dat ? mix_mask : 0;
1642 switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix)
1644 case 0: src_dat = s3->accel.bkgd_color; break;
1645 case 1: src_dat = s3->accel.frgd_color; break;
1646 case 2: src_dat = cpu_dat; break;
1647 case 3: READ(s3->accel.src + s3->accel.cx, src_dat); break;
1650 if ((compare_mode == 2 && src_dat != compare) ||
1651 (compare_mode == 3 && src_dat == compare) ||
1652 compare_mode < 2)
1654 READ(s3->accel.dest + s3->accel.dx, dest_dat);
1656 // pclog("Pattern fill : %04i, %04i (%06X) - %02X (%02X %04X %05X) %02X ", s3->accel.dx, s3->accel.dy, s3->accel.dest + s3->accel.dx, src_dat, vram[s3->accel.src + s3->accel.cx], mix_dat, s3->accel.src + s3->accel.cx, dest_dat);
1658 MIX
1660 // pclog("%02X\n", dest_dat);
1662 WRITE(s3->accel.dest + s3->accel.dx);
1666 mix_dat <<= 1;
1667 mix_dat |= 1;
1668 if (s3->bpp == 0) cpu_dat >>= 8;
1669 else cpu_dat >>= 16;
1671 if (s3->accel.cmd & 0x20)
1673 s3->accel.cx = ((s3->accel.cx + 1) & 7) | (s3->accel.cx & ~7);
1674 s3->accel.dx++;
1676 else
1678 s3->accel.cx = ((s3->accel.cx - 1) & 7) | (s3->accel.cx & ~7);
1679 s3->accel.dx--;
1681 s3->accel.sx--;
1682 if (s3->accel.sx < 0)
1684 if (s3->accel.cmd & 0x20)
1686 s3->accel.cx = ((s3->accel.cx - ((s3->accel.maj_axis_pcnt & 0xfff) + 1)) & 7) | (s3->accel.cx & ~7);
1687 s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1;
1689 else
1691 s3->accel.cx = ((s3->accel.cx + ((s3->accel.maj_axis_pcnt & 0xfff) + 1)) & 7) | (s3->accel.cx & ~7);
1692 s3->accel.dx += (s3->accel.maj_axis_pcnt & 0xfff) + 1;
1694 s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff;
1696 if (s3->accel.cmd & 0x80)
1698 s3->accel.cy = ((s3->accel.cy + 1) & 7) | (s3->accel.cy & ~7);
1699 s3->accel.dy++;
1701 else
1703 s3->accel.cy = ((s3->accel.cy - 1) & 7) | (s3->accel.cy & ~7);
1704 s3->accel.dy--;
1707 s3->accel.src = s3->accel.pattern + (s3->accel.cy * s3->width);
1708 s3->accel.dest = s3->accel.dy * s3->width;
1710 s3->accel.sy--;
1712 if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return;
1713 if (s3->accel.sy < 0)
1714 return;
1717 break;
1721 void s3_hwcursor_draw(svga_t *svga, int displine)
1723 int x;
1724 uint16_t dat[2];
1725 int xx;
1726 int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff;
1728 if (svga->interlace && svga->hwcursor_oddeven)
1729 svga->hwcursor_latch.addr += 16;
1731 // pclog("HWcursor %i %i\n", svga->hwcursor_latch.x, svga->hwcursor_latch.y);
1732 for (x = 0; x < 64; x += 16)
1734 dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 8) | svga->vram[svga->hwcursor_latch.addr + 1];
1735 dat[1] = (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3];
1736 for (xx = 0; xx < 16; xx++)
1738 if (offset >= svga->hwcursor_latch.x)
1740 if (!(dat[0] & 0x8000))
1741 ((uint32_t *)buffer32->line[displine])[offset + 32] = (dat[1] & 0x8000) ? 0xffffff : 0;
1742 else if (dat[1] & 0x8000)
1743 ((uint32_t *)buffer32->line[displine])[offset + 32] ^= 0xffffff;
1744 // pclog("Plot %i, %i (%i %i) %04X %04X\n", offset, displine, x+xx, svga_hwcursor_on, dat[0], dat[1]);
1747 offset++;
1748 dat[0] <<= 1;
1749 dat[1] <<= 1;
1751 svga->hwcursor_latch.addr += 4;
1753 if (svga->interlace && !svga->hwcursor_oddeven)
1754 svga->hwcursor_latch.addr += 16;
1758 static void s3_io_remove(s3_t *s3)
1760 io_removehandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3);
1762 io_removehandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1763 io_removehandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1764 io_removehandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1765 io_removehandler(0x82e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1766 io_removehandler(0x86e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1767 io_removehandler(0x8ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1768 io_removehandler(0x8ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1769 io_removehandler(0x92e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1770 io_removehandler(0x96e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1771 io_removehandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1772 io_removehandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1773 io_removehandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1774 io_removehandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1775 io_removehandler(0xaae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1776 io_removehandler(0xaee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1777 io_removehandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1778 io_removehandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1779 io_removehandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1780 io_removehandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1781 io_removehandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3);
1784 static void s3_io_set(s3_t *s3)
1786 s3_io_remove(s3);
1788 io_sethandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3);
1790 io_sethandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1791 io_sethandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1792 io_sethandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1793 io_sethandler(0x82e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1794 io_sethandler(0x86e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1795 io_sethandler(0x8ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1796 io_sethandler(0x8ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1797 io_sethandler(0x92e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1798 io_sethandler(0x96e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1799 io_sethandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1800 io_sethandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1801 io_sethandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1802 io_sethandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1803 io_sethandler(0xaae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1804 io_sethandler(0xaee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1805 io_sethandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1806 io_sethandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1807 io_sethandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1808 io_sethandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1809 io_sethandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3);
1813 uint8_t s3_pci_read(int func, int addr, void *p)
1815 s3_t *s3 = (s3_t *)p;
1816 svga_t *svga = &s3->svga;
1817 // pclog("S3 PCI read %08X\n", addr);
1818 switch (addr)
1820 case 0x00: return 0x33; /*'S3'*/
1821 case 0x01: return 0x53;
1823 case 0x02: return s3->id_ext_pci;
1824 case 0x03: return 0x88;
1826 case PCI_REG_COMMAND:
1827 return s3->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/
1829 case 0x07: return 1 << 1; /*Medium DEVSEL timing*/
1831 case 0x08: return 0; /*Revision ID*/
1832 case 0x09: return 0; /*Programming interface*/
1834 case 0x0a: return 0x01; /*Supports VGA interface*/
1835 case 0x0b: return 0x03;
1837 case 0x10: return 0x00; /*Linear frame buffer address*/
1838 case 0x11: return 0x00;
1839 case 0x12: return svga->crtc[0x5a] & 0x80;
1840 case 0x13: return svga->crtc[0x59];
1842 case 0x30: return s3->pci_regs[0x30] & 0x01; /*BIOS ROM address*/
1843 case 0x31: return 0x00;
1844 case 0x32: return s3->pci_regs[0x32];
1845 case 0x33: return s3->pci_regs[0x33];
1847 return 0;
1850 void s3_pci_write(int func, int addr, uint8_t val, void *p)
1852 s3_t *s3 = (s3_t *)p;
1853 svga_t *svga = &s3->svga;
1854 // pclog("s3_pci_write: addr=%02x val=%02x\n", addr, val);
1855 switch (addr)
1857 case PCI_REG_COMMAND:
1858 s3->pci_regs[PCI_REG_COMMAND] = val & 0x27;
1859 if (val & PCI_COMMAND_IO)
1860 s3_io_set(s3);
1861 else
1862 s3_io_remove(s3);
1863 s3_updatemapping(s3);
1864 break;
1866 case 0x12:
1867 svga->crtc[0x5a] = val & 0x80;
1868 s3_updatemapping(s3);
1869 break;
1870 case 0x13:
1871 svga->crtc[0x59] = val;
1872 s3_updatemapping(s3);
1873 break;
1875 case 0x30: case 0x32: case 0x33:
1876 s3->pci_regs[addr] = val;
1877 if (s3->pci_regs[0x30] & 0x01)
1879 uint32_t addr = (s3->pci_regs[0x32] << 16) | (s3->pci_regs[0x33] << 24);
1880 // pclog("S3 bios_rom enabled at %08x\n", addr);
1881 mem_mapping_set_addr(&s3->bios_rom.mapping, addr, 0x8000);
1883 else
1885 // pclog("S3 bios_rom disabled\n");
1886 mem_mapping_disable(&s3->bios_rom.mapping);
1888 return;
1892 static int vram_sizes[] =
1894 7, /*512 kB*/
1895 6, /*1 MB*/
1896 4, /*2 MB*/
1897 0,
1898 0, /*4 MB*/
1899 0,
1900 0,
1901 0,
1902 3 /*8 MB*/
1903 };
1905 static void *s3_init(char *bios_fn, int chip)
1907 s3_t *s3 = malloc(sizeof(s3_t));
1908 svga_t *svga = &s3->svga;
1909 int vram;
1910 uint32_t vram_size;
1912 memset(s3, 0, sizeof(s3_t));
1914 vram = device_get_config_int("memory");
1915 if (vram)
1916 vram_size = vram << 20;
1917 else
1918 vram_size = 512 << 10;
1919 s3->vram_mask = vram_size - 1;
1921 rom_init(&s3->bios_rom, bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
1922 if (PCI)
1923 mem_mapping_disable(&s3->bios_rom.mapping);
1925 mem_mapping_add(&s3->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, MEM_MAPPING_EXTERNAL, &s3->svga);
1926 mem_mapping_add(&s3->mmio_mapping, 0xa0000, 0x10000, s3_accel_read, NULL, NULL, s3_accel_write, s3_accel_write_w, s3_accel_write_l, NULL, MEM_MAPPING_EXTERNAL, s3);
1927 mem_mapping_disable(&s3->mmio_mapping);
1929 svga_init(&s3->svga, s3, vram_size, /*4mb - 864 supports 8mb but buggy VESA driver reports 0mb*/
1930 s3_recalctimings,
1931 s3_in, s3_out,
1932 s3_hwcursor_draw,
1933 NULL);
1935 if (PCI)
1936 svga->crtc[0x36] = 2 | (2 << 2) | (1 << 4) | (vram_sizes[vram] << 5);
1937 else
1938 svga->crtc[0x36] = 1 | (2 << 2) | (1 << 4) | (vram_sizes[vram] << 5);
1939 svga->crtc[0x37] = 1 | (7 << 5);
1941 s3_io_set(s3);
1943 pci_add(s3_pci_read, s3_pci_write, s3);
1945 s3->pci_regs[0x04] = 7;
1947 s3->pci_regs[0x30] = 0x00;
1948 s3->pci_regs[0x32] = 0x0c;
1949 s3->pci_regs[0x33] = 0x00;
1951 s3->chip = chip;
1953 return s3;
1956 void *s3_bahamas64_init()
1958 s3_t *s3 = s3_init("roms/bahamas64.bin", S3_VISION864);
1960 s3->id = 0xc1; /*Vision864P*/
1961 s3->id_ext = s3->id_ext_pci = 0xc1;
1962 s3->packed_mmio = 0;
1964 s3->getclock = sdac_getclock;
1965 s3->getclock_p = &s3->ramdac;
1967 return s3;
1970 int s3_bahamas64_available()
1972 return rom_present("roms/bahamas64.bin");
1975 void *s3_9fx_init()
1977 s3_t *s3 = s3_init("roms/s3_764.bin", S3_TRIO64);
1979 s3->id = 0xe1; /*Trio64*/
1980 s3->id_ext = s3->id_ext_pci = 0x11;
1981 s3->packed_mmio = 1;
1983 s3->getclock = s3_trio64_getclock;
1984 s3->getclock_p = s3;
1986 return s3;
1989 int s3_9fx_available()
1991 return rom_present("roms/s3_764.bin");
1994 void *s3_phoenix_trio32_init()
1996 s3_t *s3 = s3_init("roms/86C732P.bin", S3_TRIO32);
1997 svga_t *svga = &s3->svga;
1999 s3->id = 0xe1; /*Trio32*/
2000 s3->id_ext = 0x10;
2001 s3->id_ext_pci = 0x11;
2002 s3->packed_mmio = 1;
2004 s3->getclock = s3_trio64_getclock;
2005 s3->getclock_p = s3;
2007 return s3;
2010 int s3_phoenix_trio32_available()
2012 return rom_present("roms/86C732P.bin");
2015 void s3_close(void *p)
2017 s3_t *s3 = (s3_t *)p;
2019 svga_close(&s3->svga);
2021 free(s3);
2024 void s3_speed_changed(void *p)
2026 s3_t *s3 = (s3_t *)p;
2028 svga_recalctimings(&s3->svga);
2031 void s3_force_redraw(void *p)
2033 s3_t *s3 = (s3_t *)p;
2035 s3->svga.fullchange = changeframecount;
2038 int s3_add_status_info(char *s, int max_len, void *p)
2040 s3_t *s3 = (s3_t *)p;
2042 return svga_add_status_info(s, max_len, &s3->svga);
2045 static device_config_t s3_bahamas64_config[] =
2048 .name = "memory",
2049 .description = "Memory size",
2050 .type = CONFIG_SELECTION,
2051 .selection =
2054 .description = "1 MB",
2055 .value = 1
2056 },
2058 .description = "2 MB",
2059 .value = 2
2060 },
2062 .description = "4 MB",
2063 .value = 4
2064 },
2065 /*Vision864 also supports 8 MB, however the Paradise BIOS is buggy (VESA modes don't work correctly)*/
2067 .description = ""
2069 },
2070 .default_int = 4
2071 },
2073 .type = -1
2075 };
2077 static device_config_t s3_9fx_config[] =
2080 .name = "memory",
2081 .description = "Memory size",
2082 .type = CONFIG_SELECTION,
2083 .selection =
2086 .description = "1 MB",
2087 .value = 1
2088 },
2090 .description = "2 MB",
2091 .value = 2
2092 },
2093 /*Trio64 also supports 4 MB, however the Number Nine BIOS does not*/
2095 .description = ""
2097 },
2098 .default_int = 2
2099 },
2101 .type = -1
2103 };
2105 static device_config_t s3_phoenix_trio32_config[] =
2108 .name = "memory",
2109 .description = "Memory size",
2110 .type = CONFIG_SELECTION,
2111 .selection =
2114 .description = "512 KB",
2115 .value = 0
2116 },
2118 .description = "1 MB",
2119 .value = 1
2120 },
2122 .description = "2 MB",
2123 .value = 2
2124 },
2126 .description = ""
2128 },
2129 .default_int = 2
2130 },
2132 .type = -1
2134 };
2136 device_t s3_bahamas64_device =
2138 "Paradise Bahamas 64 (S3 Vision864)",
2139 0,
2140 s3_bahamas64_init,
2141 s3_close,
2142 s3_bahamas64_available,
2143 s3_speed_changed,
2144 s3_force_redraw,
2145 s3_add_status_info,
2146 s3_bahamas64_config
2147 };
2149 device_t s3_9fx_device =
2151 "Number 9 9FX (S3 Trio64)",
2152 0,
2153 s3_9fx_init,
2154 s3_close,
2155 s3_9fx_available,
2156 s3_speed_changed,
2157 s3_force_redraw,
2158 s3_add_status_info,
2159 s3_9fx_config
2160 };
2162 device_t s3_phoenix_trio32_device =
2164 "Phoenix S3 Trio32",
2165 0,
2166 s3_phoenix_trio32_init,
2167 s3_close,
2168 s3_phoenix_trio32_available,
2169 s3_speed_changed,
2170 s3_force_redraw,
2171 s3_add_status_info,
2172 s3_phoenix_trio32_config
2173 };