PCem
view src/vid_s3.c @ 154:d0d530adce12
Initial port to Linux (using Allegro).
64-bit fixes.
Some changes to aid portability.
A few other tweaks.
| author | TomW |
|---|---|
| date | Thu Sep 04 21:07:24 2014 +0100 |
| parents | 24b744b9a632 |
| children |
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;
1001 }
1004 if (addr & 0x8000)
1005 {
1006 s3_accel_out(addr & 0xffff, val, p);
1007 }
1008 else
1009 {
1010 if (s3->accel.cmd & 0x100)
1011 {
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);
1016 }
1017 }
1018 }
1020 void s3_accel_write_w(uint32_t addr, uint16_t val, void *p)
1021 {
1022 s3_t *s3 = (s3_t *)p;
1023 // pclog("Write S3 accel w %08X %04X\n", addr, val);
1024 if (addr & 0x8000)
1025 {
1026 s3_accel_write(addr, val, p);
1027 s3_accel_write(addr + 1, val >> 8, p);
1028 }
1029 else
1030 {
1031 if (s3->accel.cmd & 0x100)
1032 {
1033 if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80)
1034 {
1035 if (s3->accel.cmd & 0x1000)
1036 val = (val >> 8) | (val << 8);
1037 s3_accel_start(16, 1, val | (val << 16), 0, s3);
1038 }
1039 else
1040 s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3);
1041 }
1042 }
1043 }
1045 void s3_accel_write_l(uint32_t addr, uint32_t val, void *p)
1046 {
1047 s3_t *s3 = (s3_t *)p;
1048 // pclog("Write S3 accel l %08X %08X\n", addr, val);
1049 if (addr & 0x8000)
1050 {
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);
1055 }
1056 else
1057 {
1058 if (s3->accel.cmd & 0x100)
1059 {
1060 if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80)
1061 {
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)
1067 {
1068 s3_accel_start(16, 1, val >> 16, 0, s3);
1069 s3_accel_start(16, 1, val, 0, s3);
1070 }
1071 else if (!(s3->accel.cmd & 0x600))
1072 {
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);
1077 }
1078 }
1079 else
1080 {
1081 if ((s3->accel.cmd & 0x600) == 0x400)
1082 s3_accel_start(4, 1, 0xffffffff, val, s3);
1083 else if ((s3->accel.cmd & 0x600) == 0x200)
1084 {
1085 s3_accel_start(2, 1, 0xffffffff, val, s3);
1086 s3_accel_start(2, 1, 0xffffffff, val >> 16, s3);
1087 }
1088 else if (!(s3->accel.cmd & 0x600))
1089 {
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);
1094 }
1095 }
1096 }
1097 }
1098 }
1100 uint8_t s3_accel_read(uint32_t addr, void *p)
1101 {
1102 if (addr & 0x8000)
1103 return s3_accel_in(addr & 0xffff, p);
1104 return 0;
1105 }
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; \
1129 }
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; \
1146 }
1148 void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3)
1149 {
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)
1169 {
1170 if (s3->bpp == 3 && count == 2)
1171 {
1172 if (s3->accel.dat_count)
1173 {
1174 cpu_dat = (cpu_dat & 0xffff) | (s3->accel.dat_buf << 16);
1175 count = 4;
1176 s3->accel.dat_count = 0;
1177 }
1178 else
1179 {
1180 s3->accel.dat_buf = cpu_dat & 0xffff;
1181 s3->accel.dat_count = 1;
1182 }
1183 }
1184 if (s3->bpp == 1) count >>= 1;
1185 if (s3->bpp == 3) count >>= 2;
1186 }
1188 switch (s3->accel.cmd & 0x600)
1189 {
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;
1194 }
1196 if (s3->bpp == 0) compare &= 0xff;
1197 if (s3->bpp == 1) compare &= 0xffff;
1198 switch (s3->accel.cmd >> 13)
1199 {
1200 case 1: /*Draw line*/
1201 if (!cpu_input) /*!cpu_input is trigger to start operation*/
1202 {
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;
1209 }
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*/
1216 {
1217 while (count-- && s3->accel.sy >= 0)
1218 {
1219 if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r &&
1220 s3->accel.cy >= clip_t && s3->accel.cy <= clip_b)
1221 {
1222 switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix)
1223 {
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;
1228 }
1230 if ((compare_mode == 2 && src_dat != compare) ||
1231 (compare_mode == 3 && src_dat == compare) ||
1232 compare_mode < 2)
1233 {
1234 READ((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat);
1236 MIX
1238 WRITE((s3->accel.cy * s3->width) + s3->accel.cx);
1239 }
1240 }
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)
1250 {
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;
1259 }
1260 s3->accel.sy--;
1261 }
1262 s3->accel.cur_x = s3->accel.cx;
1263 s3->accel.cur_y = s3->accel.cy;
1264 }
1265 else /*Bresenham*/
1266 {
1267 while (count-- && s3->accel.sy >= 0)
1268 {
1269 if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r &&
1270 s3->accel.cy >= clip_t && s3->accel.cy <= clip_b)
1271 {
1272 switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix)
1273 {
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;
1278 }
1280 if ((compare_mode == 2 && src_dat != compare) ||
1281 (compare_mode == 3 && src_dat == compare) ||
1282 compare_mode < 2)
1283 {
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);
1293 }
1294 }
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)
1307 {
1308 s3->accel.err_term += s3->accel.destx_distp;
1309 /*Step minor axis*/
1310 switch (s3->accel.cmd & 0xe0)
1311 {
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;
1320 }
1321 }
1322 else
1323 s3->accel.err_term += s3->accel.desty_axstp;
1325 /*Step major axis*/
1326 switch (s3->accel.cmd & 0xe0)
1327 {
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;
1336 }
1337 s3->accel.sy--;
1338 }
1339 s3->accel.cur_x = s3->accel.cx;
1340 s3->accel.cur_y = s3->accel.cy;
1341 }
1342 break;
1344 case 2: /*Rectangle fill*/
1345 if (!cpu_input) /*!cpu_input is trigger to start operation*/
1346 {
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);
1357 }
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)
1366 {
1367 if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r &&
1368 s3->accel.cy >= clip_t && s3->accel.cy <= clip_b)
1369 {
1370 switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix)
1371 {
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;
1376 }
1378 if ((compare_mode == 2 && src_dat != compare) ||
1379 (compare_mode == 3 && src_dat == compare) ||
1380 compare_mode < 2)
1381 {
1382 READ(s3->accel.dest + s3->accel.cx, dest_dat);
1385 // 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);
1387 MIX
1389 // if (CS != 0xc000) pclog("%02X\n", dest_dat);
1391 WRITE(s3->accel.dest + s3->accel.cx);
1392 }
1393 }
1395 mix_dat <<= 1;
1396 mix_dat |= 1;
1397 if (s3->bpp == 0) cpu_dat >>= 8;
1398 else cpu_dat >>= 16;
1400 if (s3->accel.cmd & 0x20) s3->accel.cx++;
1401 else s3->accel.cx--;
1402 s3->accel.sx--;
1403 if (s3->accel.sx < 0)
1404 {
1405 if (s3->accel.cmd & 0x20) s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1;
1406 else s3->accel.cx += (s3->accel.maj_axis_pcnt & 0xfff) + 1;
1407 // s3->accel.dest -= (s3->accel.maj_axis_pcnt & 0xfff) + 1;
1408 s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff;
1410 // s3->accel.dest += s3_width;
1411 if (s3->accel.cmd & 0x80) s3->accel.cy++;
1412 else s3->accel.cy--;
1414 s3->accel.dest = s3->accel.cy * s3->width;
1415 s3->accel.sy--;
1417 if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return;
1418 if (s3->accel.sy < 0)
1419 {
1420 s3->accel.cur_x = s3->accel.cx;
1421 s3->accel.cur_y = s3->accel.cy;
1422 return;
1423 }
1424 }
1425 }
1426 break;
1428 case 6: /*BitBlt*/
1429 if (!cpu_input) /*!cpu_input is trigger to start operation*/
1430 {
1431 s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff;
1432 s3->accel.sy = s3->accel.multifunc[0] & 0xfff;
1434 s3->accel.dx = s3->accel.destx_distp & 0xfff;
1435 if (s3->accel.destx_distp & 0x1000) s3->accel.dx |= ~0xfff;
1436 s3->accel.dy = s3->accel.desty_axstp & 0xfff;
1437 if (s3->accel.desty_axstp & 0x1000) s3->accel.dy |= ~0xfff;
1439 s3->accel.cx = s3->accel.cur_x & 0xfff;
1440 if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff;
1441 s3->accel.cy = s3->accel.cur_y & 0xfff;
1442 if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff;
1444 s3->accel.src = s3->accel.cy * s3->width;
1445 s3->accel.dest = s3->accel.dy * s3->width;
1447 // 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 }
1449 if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/
1450 // if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !cpu_input) /*Mix data from CPU*/
1451 // return;
1453 if (s3->accel.sy < 0)
1454 return;
1456 frgd_mix = (s3->accel.frgd_mix >> 5) & 3;
1457 bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3;
1459 if (!cpu_input && frgd_mix == 3 && !vram_mask && !compare_mode &&
1460 (s3->accel.cmd & 0xa0) == 0xa0 && (s3->accel.frgd_mix & 0xf) == 7)
1461 {
1462 while (1)
1463 {
1464 if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r &&
1465 s3->accel.dy >= clip_t && s3->accel.dy <= clip_b)
1466 {
1467 READ(s3->accel.src + s3->accel.cx, src_dat);
1469 dest_dat = src_dat;
1471 WRITE(s3->accel.dest + s3->accel.dx);
1472 }
1474 s3->accel.cx++;
1475 s3->accel.dx++;
1476 s3->accel.sx--;
1477 if (s3->accel.sx < 0)
1478 {
1479 s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1;
1480 s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1;
1481 s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff;
1483 s3->accel.cy++;
1484 s3->accel.dy++;
1486 s3->accel.src = s3->accel.cy * s3->width;
1487 s3->accel.dest = s3->accel.dy * s3->width;
1489 s3->accel.sy--;
1491 if (s3->accel.sy < 0)
1492 {
1493 s3->accel.cur_x = s3->accel.cx;
1494 s3->accel.cur_y = s3->accel.cy;
1495 return;
1496 }
1497 }
1498 }
1499 }
1500 else
1501 {
1502 while (count-- && s3->accel.sy >= 0)
1503 {
1504 if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r &&
1505 s3->accel.dy >= clip_t && s3->accel.dy <= clip_b)
1506 {
1507 if (vram_mask)
1508 {
1509 READ(s3->accel.src + s3->accel.cx, mix_dat)
1510 mix_dat = mix_dat ? mix_mask : 0;
1511 }
1512 switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix)
1513 {
1514 case 0: src_dat = s3->accel.bkgd_color; break;
1515 case 1: src_dat = s3->accel.frgd_color; break;
1516 case 2: src_dat = cpu_dat; break;
1517 case 3: READ(s3->accel.src + s3->accel.cx, src_dat); break;
1518 }
1520 if ((compare_mode == 2 && src_dat != compare) ||
1521 (compare_mode == 3 && src_dat == compare) ||
1522 compare_mode < 2)
1523 {
1524 READ(s3->accel.dest + s3->accel.dx, dest_dat);
1526 // 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);
1528 MIX
1530 // pclog("%02X\n", dest_dat);
1532 WRITE(s3->accel.dest + s3->accel.dx);
1533 }
1534 }
1536 mix_dat <<= 1;
1537 mix_dat |= 1;
1538 if (s3->bpp == 0) cpu_dat >>= 8;
1539 else cpu_dat >>= 16;
1541 if (s3->accel.cmd & 0x20)
1542 {
1543 s3->accel.cx++;
1544 s3->accel.dx++;
1545 }
1546 else
1547 {
1548 s3->accel.cx--;
1549 s3->accel.dx--;
1550 }
1551 s3->accel.sx--;
1552 if (s3->accel.sx < 0)
1553 {
1554 if (s3->accel.cmd & 0x20)
1555 {
1556 s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1;
1557 s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1;
1558 }
1559 else
1560 {
1561 s3->accel.cx += (s3->accel.maj_axis_pcnt & 0xfff) + 1;
1562 s3->accel.dx += (s3->accel.maj_axis_pcnt & 0xfff) + 1;
1563 }
1564 s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff;
1566 if (s3->accel.cmd & 0x80)
1567 {
1568 s3->accel.cy++;
1569 s3->accel.dy++;
1570 }
1571 else
1572 {
1573 s3->accel.cy--;
1574 s3->accel.dy--;
1575 }
1577 s3->accel.src = s3->accel.cy * s3->width;
1578 s3->accel.dest = s3->accel.dy * s3->width;
1580 s3->accel.sy--;
1582 if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return;
1583 if (s3->accel.sy < 0)
1584 {
1585 s3->accel.cur_x = s3->accel.cx;
1586 s3->accel.cur_y = s3->accel.cy;
1587 return;
1588 }
1589 }
1590 }
1591 }
1592 break;
1594 case 7: /*Pattern fill - BitBlt but with source limited to 8x8*/
1595 if (!cpu_input) /*!cpu_input is trigger to start operation*/
1596 {
1597 s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff;
1598 s3->accel.sy = s3->accel.multifunc[0] & 0xfff;
1600 s3->accel.dx = s3->accel.destx_distp & 0xfff;
1601 if (s3->accel.destx_distp & 0x1000) s3->accel.dx |= ~0xfff;
1602 s3->accel.dy = s3->accel.desty_axstp & 0xfff;
1603 if (s3->accel.desty_axstp & 0x1000) s3->accel.dy |= ~0xfff;
1605 s3->accel.cx = s3->accel.cur_x & 0xfff;
1606 if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff;
1607 s3->accel.cy = s3->accel.cur_y & 0xfff;
1608 if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff;
1610 /*Align source with destination*/
1611 // s3->accel.cx = (s3->accel.cx & ~7) | (s3->accel.dx & 7);
1612 // s3->accel.cy = (s3->accel.cy & ~7) | (s3->accel.dy & 7);
1614 s3->accel.pattern = (s3->accel.cy * s3->width) + s3->accel.cx;
1615 s3->accel.dest = s3->accel.dy * s3->width;
1617 s3->accel.cx = s3->accel.dx & 7;
1618 s3->accel.cy = s3->accel.dy & 7;
1620 s3->accel.src = s3->accel.pattern + (s3->accel.cy * s3->width);
1622 // 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);
1623 // dumpregs();
1624 // exit(-1);
1625 }
1626 if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/
1627 // if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !cpu_input) /*Mix data from CPU*/
1628 // return;
1630 frgd_mix = (s3->accel.frgd_mix >> 5) & 3;
1631 bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3;
1633 while (count-- && s3->accel.sy >= 0)
1634 {
1635 if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r &&
1636 s3->accel.dy >= clip_t && s3->accel.dy <= clip_b)
1637 {
1638 if (vram_mask)
1639 {
1640 READ(s3->accel.src + s3->accel.cx, mix_dat)
1641 mix_dat = mix_dat ? mix_mask : 0;
1642 }
1643 switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix)
1644 {
1645 case 0: src_dat = s3->accel.bkgd_color; break;
1646 case 1: src_dat = s3->accel.frgd_color; break;
1647 case 2: src_dat = cpu_dat; break;
1648 case 3: READ(s3->accel.src + s3->accel.cx, src_dat); break;
1649 }
1651 if ((compare_mode == 2 && src_dat != compare) ||
1652 (compare_mode == 3 && src_dat == compare) ||
1653 compare_mode < 2)
1654 {
1655 READ(s3->accel.dest + s3->accel.dx, dest_dat);
1657 // 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);
1659 MIX
1661 // pclog("%02X\n", dest_dat);
1663 WRITE(s3->accel.dest + s3->accel.dx);
1664 }
1665 }
1667 mix_dat <<= 1;
1668 mix_dat |= 1;
1669 if (s3->bpp == 0) cpu_dat >>= 8;
1670 else cpu_dat >>= 16;
1672 if (s3->accel.cmd & 0x20)
1673 {
1674 s3->accel.cx = ((s3->accel.cx + 1) & 7) | (s3->accel.cx & ~7);
1675 s3->accel.dx++;
1676 }
1677 else
1678 {
1679 s3->accel.cx = ((s3->accel.cx - 1) & 7) | (s3->accel.cx & ~7);
1680 s3->accel.dx--;
1681 }
1682 s3->accel.sx--;
1683 if (s3->accel.sx < 0)
1684 {
1685 if (s3->accel.cmd & 0x20)
1686 {
1687 s3->accel.cx = ((s3->accel.cx - ((s3->accel.maj_axis_pcnt & 0xfff) + 1)) & 7) | (s3->accel.cx & ~7);
1688 s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1;
1689 }
1690 else
1691 {
1692 s3->accel.cx = ((s3->accel.cx + ((s3->accel.maj_axis_pcnt & 0xfff) + 1)) & 7) | (s3->accel.cx & ~7);
1693 s3->accel.dx += (s3->accel.maj_axis_pcnt & 0xfff) + 1;
1694 }
1695 s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff;
1697 if (s3->accel.cmd & 0x80)
1698 {
1699 s3->accel.cy = ((s3->accel.cy + 1) & 7) | (s3->accel.cy & ~7);
1700 s3->accel.dy++;
1701 }
1702 else
1703 {
1704 s3->accel.cy = ((s3->accel.cy - 1) & 7) | (s3->accel.cy & ~7);
1705 s3->accel.dy--;
1706 }
1708 s3->accel.src = s3->accel.pattern + (s3->accel.cy * s3->width);
1709 s3->accel.dest = s3->accel.dy * s3->width;
1711 s3->accel.sy--;
1713 if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return;
1714 if (s3->accel.sy < 0)
1715 return;
1716 }
1717 }
1718 break;
1719 }
1720 }
1722 void s3_hwcursor_draw(svga_t *svga, int displine)
1723 {
1724 int x;
1725 uint16_t dat[2];
1726 int xx;
1727 int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff;
1729 if (svga->interlace && svga->hwcursor_oddeven)
1730 svga->hwcursor_latch.addr += 16;
1732 // pclog("HWcursor %i %i\n", svga->hwcursor_latch.x, svga->hwcursor_latch.y);
1733 for (x = 0; x < 64; x += 16)
1734 {
1735 dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 8) | svga->vram[svga->hwcursor_latch.addr + 1];
1736 dat[1] = (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3];
1737 for (xx = 0; xx < 16; xx++)
1738 {
1739 if (offset >= svga->hwcursor_latch.x)
1740 {
1741 if (!(dat[0] & 0x8000))
1742 ((uint32_t *)buffer32->line[displine])[offset + 32] = (dat[1] & 0x8000) ? 0xffffff : 0;
1743 else if (dat[1] & 0x8000)
1744 ((uint32_t *)buffer32->line[displine])[offset + 32] ^= 0xffffff;
1745 // pclog("Plot %i, %i (%i %i) %04X %04X\n", offset, displine, x+xx, svga_hwcursor_on, dat[0], dat[1]);
1746 }
1748 offset++;
1749 dat[0] <<= 1;
1750 dat[1] <<= 1;
1751 }
1752 svga->hwcursor_latch.addr += 4;
1753 }
1754 if (svga->interlace && !svga->hwcursor_oddeven)
1755 svga->hwcursor_latch.addr += 16;
1756 }
1759 static void s3_io_remove(s3_t *s3)
1760 {
1761 io_removehandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3);
1763 io_removehandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1764 io_removehandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1765 io_removehandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1766 io_removehandler(0x82e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1767 io_removehandler(0x86e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1768 io_removehandler(0x8ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1769 io_removehandler(0x8ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1770 io_removehandler(0x92e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1771 io_removehandler(0x96e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1772 io_removehandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1773 io_removehandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1774 io_removehandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1775 io_removehandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1776 io_removehandler(0xaae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1777 io_removehandler(0xaee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1778 io_removehandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1779 io_removehandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1780 io_removehandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1781 io_removehandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1782 io_removehandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3);
1783 }
1785 static void s3_io_set(s3_t *s3)
1786 {
1787 s3_io_remove(s3);
1789 io_sethandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3);
1791 io_sethandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1792 io_sethandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1793 io_sethandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1794 io_sethandler(0x82e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1795 io_sethandler(0x86e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1796 io_sethandler(0x8ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1797 io_sethandler(0x8ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1798 io_sethandler(0x92e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1799 io_sethandler(0x96e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1800 io_sethandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1801 io_sethandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1802 io_sethandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1803 io_sethandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1804 io_sethandler(0xaae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1805 io_sethandler(0xaee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1806 io_sethandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1807 io_sethandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1808 io_sethandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1809 io_sethandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3);
1810 io_sethandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3);
1811 }
1814 uint8_t s3_pci_read(int func, int addr, void *p)
1815 {
1816 s3_t *s3 = (s3_t *)p;
1817 svga_t *svga = &s3->svga;
1818 // pclog("S3 PCI read %08X\n", addr);
1819 switch (addr)
1820 {
1821 case 0x00: return 0x33; /*'S3'*/
1822 case 0x01: return 0x53;
1824 case 0x02: return s3->id_ext_pci;
1825 case 0x03: return 0x88;
1827 case PCI_REG_COMMAND:
1828 return s3->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/
1830 case 0x07: return 1 << 1; /*Medium DEVSEL timing*/
1832 case 0x08: return 0; /*Revision ID*/
1833 case 0x09: return 0; /*Programming interface*/
1835 case 0x0a: return 0x01; /*Supports VGA interface*/
1836 case 0x0b: return 0x03;
1838 case 0x10: return 0x00; /*Linear frame buffer address*/
1839 case 0x11: return 0x00;
1840 case 0x12: return svga->crtc[0x5a] & 0x80;
1841 case 0x13: return svga->crtc[0x59];
1843 case 0x30: return s3->pci_regs[0x30] & 0x01; /*BIOS ROM address*/
1844 case 0x31: return 0x00;
1845 case 0x32: return s3->pci_regs[0x32];
1846 case 0x33: return s3->pci_regs[0x33];
1847 }
1848 return 0;
1849 }
1851 void s3_pci_write(int func, int addr, uint8_t val, void *p)
1852 {
1853 s3_t *s3 = (s3_t *)p;
1854 svga_t *svga = &s3->svga;
1855 // pclog("s3_pci_write: addr=%02x val=%02x\n", addr, val);
1856 switch (addr)
1857 {
1858 case PCI_REG_COMMAND:
1859 s3->pci_regs[PCI_REG_COMMAND] = val & 0x27;
1860 if (val & PCI_COMMAND_IO)
1861 s3_io_set(s3);
1862 else
1863 s3_io_remove(s3);
1864 s3_updatemapping(s3);
1865 break;
1867 case 0x12:
1868 svga->crtc[0x5a] = val & 0x80;
1869 s3_updatemapping(s3);
1870 break;
1871 case 0x13:
1872 svga->crtc[0x59] = val;
1873 s3_updatemapping(s3);
1874 break;
1876 case 0x30: case 0x32: case 0x33:
1877 s3->pci_regs[addr] = val;
1878 if (s3->pci_regs[0x30] & 0x01)
1879 {
1880 uint32_t addr = (s3->pci_regs[0x32] << 16) | (s3->pci_regs[0x33] << 24);
1881 // pclog("S3 bios_rom enabled at %08x\n", addr);
1882 mem_mapping_set_addr(&s3->bios_rom.mapping, addr, 0x8000);
1883 }
1884 else
1885 {
1886 // pclog("S3 bios_rom disabled\n");
1887 mem_mapping_disable(&s3->bios_rom.mapping);
1888 }
1889 return;
1890 }
1891 }
1893 static int vram_sizes[] =
1894 {
1895 7, /*512 kB*/
1896 6, /*1 MB*/
1897 4, /*2 MB*/
1898 0,
1899 0, /*4 MB*/
1900 0,
1901 0,
1902 0,
1903 3 /*8 MB*/
1904 };
1906 static void *s3_init(char *bios_fn, int chip)
1907 {
1908 s3_t *s3 = malloc(sizeof(s3_t));
1909 svga_t *svga = &s3->svga;
1910 int vram;
1911 uint32_t vram_size;
1913 memset(s3, 0, sizeof(s3_t));
1915 vram = device_get_config_int("memory");
1916 if (vram)
1917 vram_size = vram << 20;
1918 else
1919 vram_size = 512 << 10;
1920 s3->vram_mask = vram_size - 1;
1922 rom_init(&s3->bios_rom, bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
1923 if (PCI)
1924 mem_mapping_disable(&s3->bios_rom.mapping);
1926 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);
1927 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);
1928 mem_mapping_disable(&s3->mmio_mapping);
1930 svga_init(&s3->svga, s3, vram_size, /*4mb - 864 supports 8mb but buggy VESA driver reports 0mb*/
1931 s3_recalctimings,
1932 s3_in, s3_out,
1933 s3_hwcursor_draw,
1934 NULL);
1936 if (PCI)
1937 svga->crtc[0x36] = 2 | (3 << 2) | (1 << 4) | (vram_sizes[vram] << 5);
1938 else
1939 svga->crtc[0x36] = 1 | (3 << 2) | (1 << 4) | (vram_sizes[vram] << 5);
1940 svga->crtc[0x37] = 1 | (7 << 5);
1942 s3_io_set(s3);
1944 pci_add(s3_pci_read, s3_pci_write, s3);
1946 s3->pci_regs[0x04] = 7;
1948 s3->pci_regs[0x30] = 0x00;
1949 s3->pci_regs[0x32] = 0x0c;
1950 s3->pci_regs[0x33] = 0x00;
1952 s3->chip = chip;
1954 return s3;
1955 }
1957 void *s3_bahamas64_init()
1958 {
1959 s3_t *s3 = s3_init("roms/bahamas64.BIN", S3_VISION864);
1961 s3->id = 0xc1; /*Vision864P*/
1962 s3->id_ext = s3->id_ext_pci = 0xc1;
1963 s3->packed_mmio = 0;
1965 s3->getclock = sdac_getclock;
1966 s3->getclock_p = &s3->ramdac;
1968 return s3;
1969 }
1971 int s3_bahamas64_available()
1972 {
1973 return rom_present("roms/bahamas64.BIN");
1974 }
1976 void *s3_9fx_init()
1977 {
1978 s3_t *s3 = s3_init("roms/s3_764.bin", S3_TRIO64);
1980 s3->id = 0xe1; /*Trio64*/
1981 s3->id_ext = s3->id_ext_pci = 0x11;
1982 s3->packed_mmio = 1;
1984 s3->getclock = s3_trio64_getclock;
1985 s3->getclock_p = s3;
1987 return s3;
1988 }
1990 int s3_9fx_available()
1991 {
1992 return rom_present("roms/s3_764.bin");
1993 }
1995 void *s3_phoenix_trio32_init()
1996 {
1997 s3_t *s3 = s3_init("roms/86C732P.bin", S3_TRIO32);
1998 svga_t *svga = &s3->svga;
2000 s3->id = 0xe1; /*Trio32*/
2001 s3->id_ext = 0x10;
2002 s3->id_ext_pci = 0x11;
2003 s3->packed_mmio = 1;
2005 s3->getclock = s3_trio64_getclock;
2006 s3->getclock_p = s3;
2008 return s3;
2009 }
2011 int s3_phoenix_trio32_available()
2012 {
2013 return rom_present("roms/86C732P.bin");
2014 }
2016 void *s3_phoenix_trio64_init()
2017 {
2018 s3_t *s3 = s3_init("roms/86c764x1.bin", S3_TRIO64);
2019 svga_t *svga = &s3->svga;
2021 s3->id = 0xe1; /*Trio64*/
2022 s3->id_ext = s3->id_ext_pci = 0x11;
2023 s3->packed_mmio = 1;
2025 s3->getclock = s3_trio64_getclock;
2026 s3->getclock_p = s3;
2028 return s3;
2029 }
2031 int s3_phoenix_trio64_available()
2032 {
2033 return rom_present("roms/86c764x1.bin");
2034 }
2036 void s3_close(void *p)
2037 {
2038 s3_t *s3 = (s3_t *)p;
2040 svga_close(&s3->svga);
2042 free(s3);
2043 }
2045 void s3_speed_changed(void *p)
2046 {
2047 s3_t *s3 = (s3_t *)p;
2049 svga_recalctimings(&s3->svga);
2050 }
2052 void s3_force_redraw(void *p)
2053 {
2054 s3_t *s3 = (s3_t *)p;
2056 s3->svga.fullchange = changeframecount;
2057 }
2059 void s3_add_status_info(char *s, int max_len, void *p)
2060 {
2061 s3_t *s3 = (s3_t *)p;
2063 svga_add_status_info(s, max_len, &s3->svga);
2064 }
2066 static device_config_t s3_bahamas64_config[] =
2067 {
2068 {
2069 .name = "memory",
2070 .description = "Memory size",
2071 .type = CONFIG_SELECTION,
2072 .selection =
2073 {
2074 {
2075 .description = "1 MB",
2076 .value = 1
2077 },
2078 {
2079 .description = "2 MB",
2080 .value = 2
2081 },
2082 {
2083 .description = "4 MB",
2084 .value = 4
2085 },
2086 /*Vision864 also supports 8 MB, however the Paradise BIOS is buggy (VESA modes don't work correctly)*/
2087 {
2088 .description = ""
2089 }
2090 },
2091 .default_int = 4
2092 },
2093 {
2094 .type = -1
2095 }
2096 };
2098 static device_config_t s3_9fx_config[] =
2099 {
2100 {
2101 .name = "memory",
2102 .description = "Memory size",
2103 .type = CONFIG_SELECTION,
2104 .selection =
2105 {
2106 {
2107 .description = "1 MB",
2108 .value = 1
2109 },
2110 {
2111 .description = "2 MB",
2112 .value = 2
2113 },
2114 /*Trio64 also supports 4 MB, however the Number Nine BIOS does not*/
2115 {
2116 .description = ""
2117 }
2118 },
2119 .default_int = 2
2120 },
2121 {
2122 .type = -1
2123 }
2124 };
2126 static device_config_t s3_phoenix_trio32_config[] =
2127 {
2128 {
2129 .name = "memory",
2130 .description = "Memory size",
2131 .type = CONFIG_SELECTION,
2132 .selection =
2133 {
2134 {
2135 .description = "512 KB",
2136 .value = 0
2137 },
2138 {
2139 .description = "1 MB",
2140 .value = 1
2141 },
2142 {
2143 .description = "2 MB",
2144 .value = 2
2145 },
2146 {
2147 .description = ""
2148 }
2149 },
2150 .default_int = 2
2151 },
2152 {
2153 .type = -1
2154 }
2155 };
2157 static device_config_t s3_phoenix_trio64_config[] =
2158 {
2159 {
2160 .name = "memory",
2161 .description = "Memory size",
2162 .type = CONFIG_SELECTION,
2163 .selection =
2164 {
2165 {
2166 .description = "512 KB",
2167 .value = 0
2168 },
2169 {
2170 .description = "1 MB",
2171 .value = 1
2172 },
2173 {
2174 .description = "2 MB",
2175 .value = 2
2176 },
2177 {
2178 .description = "4 MB",
2179 .value = 4
2180 },
2181 {
2182 .description = ""
2183 }
2184 },
2185 .default_int = 2
2186 },
2187 {
2188 .type = -1
2189 }
2190 };
2192 device_t s3_bahamas64_device =
2193 {
2194 "Paradise Bahamas 64 (S3 Vision864)",
2195 0,
2196 s3_bahamas64_init,
2197 s3_close,
2198 s3_bahamas64_available,
2199 s3_speed_changed,
2200 s3_force_redraw,
2201 s3_add_status_info,
2202 s3_bahamas64_config
2203 };
2205 device_t s3_9fx_device =
2206 {
2207 "Number 9 9FX (S3 Trio64)",
2208 0,
2209 s3_9fx_init,
2210 s3_close,
2211 s3_9fx_available,
2212 s3_speed_changed,
2213 s3_force_redraw,
2214 s3_add_status_info,
2215 s3_9fx_config
2216 };
2218 device_t s3_phoenix_trio32_device =
2219 {
2220 "Phoenix S3 Trio32",
2221 0,
2222 s3_phoenix_trio32_init,
2223 s3_close,
2224 s3_phoenix_trio32_available,
2225 s3_speed_changed,
2226 s3_force_redraw,
2227 s3_add_status_info,
2228 s3_phoenix_trio32_config
2229 };
2231 device_t s3_phoenix_trio64_device =
2232 {
2233 "Phoenix S3 Trio64",
2234 0,
2235 s3_phoenix_trio64_init,
2236 s3_close,
2237 s3_phoenix_trio64_available,
2238 s3_speed_changed,
2239 s3_force_redraw,
2240 s3_add_status_info,
2241 s3_phoenix_trio64_config
2242 };
