PCem

view src/vid_s3.c @ 120:47132154ffe7

Added emulation of Phoenix Trio32. Based on patch from Battler. Paradise Bahamas 64, Number Nine 9FX and Phoenix Trio32 now have configurable memory sizes.
author TomW
date Wed Jul 09 21:45:42 2014 +0100
parents 036dc3a418ac
children 173e1f058566
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 // pclog("HWcursor %i %i\n", svga->hwcursor_latch.x, svga->hwcursor_latch.y);
1729 for (x = 0; x < 64; x += 16)
1731 dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 8) | svga->vram[svga->hwcursor_latch.addr + 1];
1732 dat[1] = (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3];
1733 for (xx = 0; xx < 16; xx++)
1735 if (offset >= svga->hwcursor_latch.x)
1737 if (!(dat[0] & 0x8000))
1738 ((uint32_t *)buffer32->line[displine])[offset + 32] = (dat[1] & 0x8000) ? 0xffffff : 0;
1739 else if (dat[1] & 0x8000)
1740 ((uint32_t *)buffer32->line[displine])[offset + 32] ^= 0xffffff;
1741 // pclog("Plot %i, %i (%i %i) %04X %04X\n", offset, displine, x+xx, svga_hwcursor_on, dat[0], dat[1]);
1744 offset++;
1745 dat[0] <<= 1;
1746 dat[1] <<= 1;
1748 svga->hwcursor_latch.addr += 4;
1753 static void s3_io_remove(s3_t *s3)
1755 io_removehandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3);
1757 io_removehandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1758 io_removehandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1759 io_removehandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1760 io_removehandler(0x82e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1761 io_removehandler(0x86e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1762 io_removehandler(0x8ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1763 io_removehandler(0x8ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1764 io_removehandler(0x92e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1765 io_removehandler(0x96e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1766 io_removehandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1767 io_removehandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1768 io_removehandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1769 io_removehandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1770 io_removehandler(0xaae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1771 io_removehandler(0xaee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1772 io_removehandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1773 io_removehandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1774 io_removehandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1775 io_removehandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1776 io_removehandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3);
1779 static void s3_io_set(s3_t *s3)
1781 s3_io_remove(s3);
1783 io_sethandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3);
1785 io_sethandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1786 io_sethandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1787 io_sethandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1788 io_sethandler(0x82e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1789 io_sethandler(0x86e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1790 io_sethandler(0x8ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1791 io_sethandler(0x8ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1792 io_sethandler(0x92e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1793 io_sethandler(0x96e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1794 io_sethandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1795 io_sethandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1796 io_sethandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1797 io_sethandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1798 io_sethandler(0xaae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1799 io_sethandler(0xaee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1800 io_sethandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1801 io_sethandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1802 io_sethandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1803 io_sethandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1804 io_sethandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3);
1808 uint8_t s3_pci_read(int func, int addr, void *p)
1810 s3_t *s3 = (s3_t *)p;
1811 svga_t *svga = &s3->svga;
1812 // pclog("S3 PCI read %08X\n", addr);
1813 switch (addr)
1815 case 0x00: return 0x33; /*'S3'*/
1816 case 0x01: return 0x53;
1818 case 0x02: return s3->id_ext_pci;
1819 case 0x03: return 0x88;
1821 case PCI_REG_COMMAND:
1822 return s3->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/
1824 case 0x07: return 1 << 1; /*Medium DEVSEL timing*/
1826 case 0x08: return 0; /*Revision ID*/
1827 case 0x09: return 0; /*Programming interface*/
1829 case 0x0a: return 0x01; /*Supports VGA interface*/
1830 case 0x0b: return 0x03;
1832 case 0x10: return 0x00; /*Linear frame buffer address*/
1833 case 0x11: return 0x00;
1834 case 0x12: return svga->crtc[0x5a] & 0x80;
1835 case 0x13: return svga->crtc[0x59];
1837 case 0x30: return s3->pci_regs[0x30] & 0x01; /*BIOS ROM address*/
1838 case 0x31: return 0x00;
1839 case 0x32: return s3->pci_regs[0x32];
1840 case 0x33: return s3->pci_regs[0x33];
1842 return 0;
1845 void s3_pci_write(int func, int addr, uint8_t val, void *p)
1847 s3_t *s3 = (s3_t *)p;
1848 svga_t *svga = &s3->svga;
1849 // pclog("s3_pci_write: addr=%02x val=%02x\n", addr, val);
1850 switch (addr)
1852 case PCI_REG_COMMAND:
1853 s3->pci_regs[PCI_REG_COMMAND] = val & 0x27;
1854 if (val & PCI_COMMAND_IO)
1855 s3_io_set(s3);
1856 else
1857 s3_io_remove(s3);
1858 s3_updatemapping(s3);
1859 break;
1861 case 0x12:
1862 svga->crtc[0x5a] = val & 0x80;
1863 s3_updatemapping(s3);
1864 break;
1865 case 0x13:
1866 svga->crtc[0x59] = val;
1867 s3_updatemapping(s3);
1868 break;
1870 case 0x30: case 0x32: case 0x33:
1871 s3->pci_regs[addr] = val;
1872 if (s3->pci_regs[0x30] & 0x01)
1874 uint32_t addr = (s3->pci_regs[0x32] << 16) | (s3->pci_regs[0x33] << 24);
1875 // pclog("S3 bios_rom enabled at %08x\n", addr);
1876 mem_mapping_set_addr(&s3->bios_rom.mapping, addr, 0x8000);
1878 else
1880 // pclog("S3 bios_rom disabled\n");
1881 mem_mapping_disable(&s3->bios_rom.mapping);
1883 return;
1887 static int vram_sizes[] =
1889 7, /*512 kB*/
1890 6, /*1 MB*/
1891 4, /*2 MB*/
1892 0,
1893 0, /*4 MB*/
1894 0,
1895 0,
1896 0,
1897 3 /*8 MB*/
1898 };
1900 static void *s3_init(char *bios_fn, int chip)
1902 s3_t *s3 = malloc(sizeof(s3_t));
1903 svga_t *svga = &s3->svga;
1904 int vram;
1905 uint32_t vram_size;
1907 memset(s3, 0, sizeof(s3_t));
1909 vram = device_get_config_int("memory");
1910 if (vram)
1911 vram_size = vram << 20;
1912 else
1913 vram_size = 512 << 10;
1914 s3->vram_mask = vram_size - 1;
1916 rom_init(&s3->bios_rom, bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
1917 if (PCI)
1918 mem_mapping_disable(&s3->bios_rom.mapping);
1920 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);
1921 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);
1922 mem_mapping_disable(&s3->mmio_mapping);
1924 svga_init(&s3->svga, s3, vram_size, /*4mb - 864 supports 8mb but buggy VESA driver reports 0mb*/
1925 s3_recalctimings,
1926 s3_in, s3_out,
1927 s3_hwcursor_draw,
1928 NULL);
1930 if (PCI)
1931 svga->crtc[0x36] = 2 | (2 << 2) | (1 << 4) | (vram_sizes[vram] << 5);
1932 else
1933 svga->crtc[0x36] = 1 | (2 << 2) | (1 << 4) | (vram_sizes[vram] << 5);
1934 svga->crtc[0x37] = 1 | (7 << 5);
1936 s3_io_set(s3);
1938 pci_add(s3_pci_read, s3_pci_write, s3);
1940 s3->pci_regs[0x04] = 7;
1942 s3->pci_regs[0x30] = 0x00;
1943 s3->pci_regs[0x32] = 0x0c;
1944 s3->pci_regs[0x33] = 0x00;
1946 s3->chip = chip;
1948 return s3;
1951 void *s3_bahamas64_init()
1953 s3_t *s3 = s3_init("roms/bahamas64.bin", S3_VISION864);
1955 s3->id = 0xc1; /*Vision864P*/
1956 s3->id_ext = s3->id_ext_pci = 0xc1;
1957 s3->packed_mmio = 0;
1959 s3->getclock = sdac_getclock;
1960 s3->getclock_p = &s3->ramdac;
1962 return s3;
1965 int s3_bahamas64_available()
1967 return rom_present("roms/bahamas64.bin");
1970 void *s3_9fx_init()
1972 s3_t *s3 = s3_init("roms/s3_764.bin", S3_TRIO64);
1974 s3->id = 0xe1; /*Trio64*/
1975 s3->id_ext = s3->id_ext_pci = 0x11;
1976 s3->packed_mmio = 1;
1978 s3->getclock = s3_trio64_getclock;
1979 s3->getclock_p = s3;
1981 return s3;
1984 int s3_9fx_available()
1986 return rom_present("roms/s3_764.bin");
1989 void *s3_phoenix_trio32_init()
1991 s3_t *s3 = s3_init("roms/86C732P.bin", S3_TRIO32);
1992 svga_t *svga = &s3->svga;
1994 s3->id = 0xe1; /*Trio32*/
1995 s3->id_ext = 0x10;
1996 s3->id_ext_pci = 0x11;
1997 s3->packed_mmio = 1;
1999 s3->getclock = s3_trio64_getclock;
2000 s3->getclock_p = s3;
2002 return s3;
2005 int s3_phoenix_trio32_available()
2007 return rom_present("roms/86C732P.bin");
2010 void s3_close(void *p)
2012 s3_t *s3 = (s3_t *)p;
2014 svga_close(&s3->svga);
2016 free(s3);
2019 void s3_speed_changed(void *p)
2021 s3_t *s3 = (s3_t *)p;
2023 svga_recalctimings(&s3->svga);
2026 void s3_force_redraw(void *p)
2028 s3_t *s3 = (s3_t *)p;
2030 s3->svga.fullchange = changeframecount;
2033 int s3_add_status_info(char *s, int max_len, void *p)
2035 s3_t *s3 = (s3_t *)p;
2037 return svga_add_status_info(s, max_len, &s3->svga);
2040 static device_config_t s3_bahamas64_config[] =
2043 .name = "memory",
2044 .description = "Memory size",
2045 .type = CONFIG_SELECTION,
2046 .selection =
2049 .description = "1 MB",
2050 .value = 1
2051 },
2053 .description = "2 MB",
2054 .value = 2
2055 },
2057 .description = "4 MB",
2058 .value = 4
2059 },
2060 /*Vision864 also supports 8 MB, however the Paradise BIOS is buggy (VESA modes don't work correctly)*/
2062 .description = ""
2064 },
2065 .default_int = 4
2066 },
2068 .type = -1
2070 };
2072 static device_config_t s3_9fx_config[] =
2075 .name = "memory",
2076 .description = "Memory size",
2077 .type = CONFIG_SELECTION,
2078 .selection =
2081 .description = "1 MB",
2082 .value = 1
2083 },
2085 .description = "2 MB",
2086 .value = 2
2087 },
2088 /*Trio64 also supports 4 MB, however the Number Nine BIOS does not*/
2090 .description = ""
2092 },
2093 .default_int = 2
2094 },
2096 .type = -1
2098 };
2100 static device_config_t s3_phoenix_trio32_config[] =
2103 .name = "memory",
2104 .description = "Memory size",
2105 .type = CONFIG_SELECTION,
2106 .selection =
2109 .description = "512 KB",
2110 .value = 0
2111 },
2113 .description = "1 MB",
2114 .value = 1
2115 },
2117 .description = "2 MB",
2118 .value = 2
2119 },
2121 .description = ""
2123 },
2124 .default_int = 2
2125 },
2127 .type = -1
2129 };
2131 device_t s3_bahamas64_device =
2133 "Paradise Bahamas 64 (S3 Vision864)",
2134 0,
2135 s3_bahamas64_init,
2136 s3_close,
2137 s3_bahamas64_available,
2138 s3_speed_changed,
2139 s3_force_redraw,
2140 s3_add_status_info,
2141 s3_bahamas64_config
2142 };
2144 device_t s3_9fx_device =
2146 "Number 9 9FX (S3 Trio64)",
2147 0,
2148 s3_9fx_init,
2149 s3_close,
2150 s3_9fx_available,
2151 s3_speed_changed,
2152 s3_force_redraw,
2153 s3_add_status_info,
2154 s3_9fx_config
2155 };
2157 device_t s3_phoenix_trio32_device =
2159 "Phoenix S3 Trio32",
2160 0,
2161 s3_phoenix_trio32_init,
2162 s3_close,
2163 s3_phoenix_trio32_available,
2164 s3_speed_changed,
2165 s3_force_redraw,
2166 s3_add_status_info,
2167 s3_phoenix_trio32_config
2168 };