PCem
view src/vid_s3_virge.c @ 113:f749363ad763
Added per-device configuration.
Reworked configuration parser a bit.
Added configuration for S3 ViRGE and 8-bit Sound Blasters.
IRQ 2 routed to IRQ 9 on AT machines.
| author | TomW |
|---|---|
| date | Mon Jun 30 21:31:28 2014 +0100 |
| parents | 036dc3a418ac |
| children | 9834054948fc |
line source
1 /*S3 ViRGE 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_virge.h"
11 #include "vid_svga.h"
12 #include "vid_svga_render.h"
14 static uint64_t virge_time = 0;
15 static uint64_t status_time = 0;
16 static int reg_writes = 0;
18 typedef struct virge_t
19 {
20 mem_mapping_t linear_mapping;
21 mem_mapping_t mmio_mapping;
22 mem_mapping_t new_mmio_mapping;
24 rom_t bios_rom;
26 svga_t svga;
28 uint8_t bank;
29 uint8_t ma_ext;
30 int width;
31 int bpp;
33 uint8_t virge_id, virge_id_high, virge_id_low, virge_rev;
35 uint32_t linear_base, linear_size;
37 uint8_t pci_regs[256];
39 int is_375;
41 int bilinear_enabled;
42 int memory_size;
44 int pixel_count, tri_count;
46 struct
47 {
48 uint32_t src_base;
49 uint32_t dest_base;
50 int clip_l, clip_r, clip_t, clip_b;
51 int dest_str, src_str;
52 uint32_t mono_pat_0;
53 uint32_t mono_pat_1;
54 uint32_t pat_bg_clr;
55 uint32_t pat_fg_clr;
56 uint32_t src_bg_clr;
57 uint32_t src_fg_clr;
58 uint32_t cmd_set;
59 int r_width, r_height;
60 int rsrc_x, rsrc_y;
61 int rdest_x, rdest_y;
63 int lxend0, lxend1;
64 int32_t ldx;
65 uint32_t lxstart, lystart;
66 int lycnt;
67 int line_dir;
69 int src_x, src_y;
70 int dest_x, dest_y;
71 int w, h;
72 uint8_t rop;
74 int data_left_count;
75 uint32_t data_left;
77 uint32_t pattern_8[8*8];
78 uint32_t pattern_16[8*8];
79 uint32_t pattern_32[8*8];
82 uint32_t z_base;
83 uint32_t z_str;
85 uint32_t tex_base;
86 uint32_t tex_bdr_clr;
87 uint32_t tbv, tbu;
88 int32_t TdVdX, TdUdX;
89 int32_t TdVdY, TdUdY;
90 uint32_t tus, tvs;
92 int32_t TdZdX, TdZdY;
93 uint32_t tzs;
95 int32_t TdWdX, TdWdY;
96 uint32_t tws;
98 int32_t TdDdX, TdDdY;
99 uint32_t tds;
101 int16_t TdGdX, TdBdX, TdRdX, TdAdX;
102 int16_t TdGdY, TdBdY, TdRdY, TdAdY;
103 uint32_t tgs, tbs, trs, tas;
105 uint32_t TdXdY12;
106 uint32_t txend12;
107 uint32_t TdXdY01;
108 uint32_t txend01;
109 uint32_t TdXdY02;
110 uint32_t txs;
111 uint32_t tys;
112 int ty01, ty12, tlr;
113 } s3d;
115 struct
116 {
117 uint32_t pri_ctrl;
118 uint32_t chroma_ctrl;
119 uint32_t sec_ctrl;
120 uint32_t chroma_upper_bound;
121 uint32_t sec_filter;
122 uint32_t blend_ctrl;
123 uint32_t pri_fb0, pri_fb1;
124 uint32_t pri_stride;
125 uint32_t buffer_ctrl;
126 uint32_t sec_fb0, sec_fb1;
127 uint32_t sec_stride;
128 uint32_t overlay_ctrl;
129 int32_t k1_vert_scale;
130 int32_t k2_vert_scale;
131 int32_t dda_vert_accumulator;
132 int32_t k1_horiz_scale;
133 int32_t k2_horiz_scale;
134 int32_t dda_horiz_accumulator;
135 uint32_t fifo_ctrl;
136 uint32_t pri_start;
137 uint32_t pri_size;
138 uint32_t sec_start;
139 uint32_t sec_size;
141 int sdif;
143 int pri_x, pri_y, pri_w, pri_h;
144 int sec_x, sec_y, sec_w, sec_h;
145 } streams;
146 } virge_t;
148 static void s3_virge_recalctimings(svga_t *svga);
149 static void s3_virge_updatemapping(virge_t *virge);
151 static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat);
153 static void s3_virge_triangle(virge_t *virge);
155 static uint8_t s3_virge_mmio_read(uint32_t addr, void *p);
156 static uint16_t s3_virge_mmio_read_w(uint32_t addr, void *p);
157 static uint32_t s3_virge_mmio_read_l(uint32_t addr, void *p);
158 static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p);
159 static void s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *p);
160 static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p);
162 enum
163 {
164 CMD_SET_AE = 1,
165 CMD_SET_HC = (1 << 1),
167 CMD_SET_FORMAT_MASK = (7 << 2),
168 CMD_SET_FORMAT_8 = (0 << 2),
169 CMD_SET_FORMAT_16 = (1 << 2),
170 CMD_SET_FORMAT_24 = (2 << 2),
172 CMD_SET_MS = (1 << 6),
173 CMD_SET_IDS = (1 << 7),
174 CMD_SET_MP = (1 << 8),
175 CMD_SET_TP = (1 << 9),
177 CMD_SET_ITA_MASK = (3 << 10),
178 CMD_SET_ITA_BYTE = (0 << 10),
179 CMD_SET_ITA_WORD = (1 << 10),
180 CMD_SET_ITA_DWORD = (2 << 10),
182 CMD_SET_ZB_MODE = (3 << 24),
184 CMD_SET_XP = (1 << 25),
185 CMD_SET_YP = (1 << 26),
187 CMD_SET_COMMAND_MASK = (15 << 27)
188 };
190 #define CMD_SET_ABC_SRC (1 << 18)
191 #define CMD_SET_ABC_ENABLE (1 << 19)
192 #define CMD_SET_TWE (1 << 26)
194 enum
195 {
196 CMD_SET_COMMAND_BITBLT = (0 << 27),
197 CMD_SET_COMMAND_RECTFILL = (2 << 27),
198 CMD_SET_COMMAND_LINE = (3 << 27),
199 CMD_SET_COMMAND_NOP = (15 << 27)
200 };
202 static void s3_virge_out(uint16_t addr, uint8_t val, void *p)
203 {
204 virge_t *virge = (virge_t *)p;
205 svga_t *svga = &virge->svga;
206 uint8_t old;
208 if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1))
209 addr ^= 0x60;
211 // pclog("S3 out %04X %02X %04X:%08X %04X %04X %i\n", addr, val, CS, pc, ES, BX, ins);
213 switch (addr)
214 {
215 case 0x3c5:
216 if (svga->seqaddr >= 0x10)
217 {
218 svga->seqregs[svga->seqaddr & 0x1f]=val;
219 s3_virge_recalctimings(svga);
220 return;
221 }
222 if (svga->seqaddr == 4) /*Chain-4 - update banking*/
223 {
224 if (val & 8) svga->write_bank = svga->read_bank = virge->bank << 16;
225 else svga->write_bank = svga->read_bank = virge->bank << 14;
226 }
227 break;
229 //case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9:
230 // pclog("Write RAMDAC %04X %02X %04X:%04X\n", addr, val, CS, pc);
231 //sdac_ramdac_out(addr,val);
232 //return;
234 case 0x3d4:
235 svga->crtcreg = val;// & 0x7f;
236 return;
237 case 0x3d5:
238 //pclog("Write CRTC R%02X %02X %04x(%08x):%08x\n", svga->crtcreg, val, CS, cs, pc);
239 if (svga->crtcreg <= 7 && svga->crtc[0x11] & 0x80)
240 return;
241 if (svga->crtcreg >= 0x20 && svga->crtcreg != 0x38 && (svga->crtc[0x38] & 0xcc) != 0x48)
242 return;
243 if (svga->crtcreg >= 0x80)
244 return;
245 old = svga->crtc[svga->crtcreg];
246 svga->crtc[svga->crtcreg] = val;
247 switch (svga->crtcreg)
248 {
249 case 0x31:
250 virge->ma_ext = (virge->ma_ext & 0x1c) | ((val & 0x30) >> 4);
251 svga->vrammask = (val & 8) ? 0x3fffff : 0x3ffff;
252 break;
254 case 0x50:
255 switch (svga->crtc[0x50] & 0xc1)
256 {
257 case 0x00: virge->width = (svga->crtc[0x31] & 2) ? 2048 : 1024; break;
258 case 0x01: virge->width = 1152; break;
259 case 0x40: virge->width = 640; break;
260 case 0x80: virge->width = 800; break;
261 case 0x81: virge->width = 1600; break;
262 case 0xc0: virge->width = 1280; break;
263 }
264 virge->bpp = (svga->crtc[0x50] >> 4) & 3;
265 break;
266 case 0x69:
267 virge->ma_ext = val & 0x1f;
268 break;
270 case 0x35:
271 virge->bank = (virge->bank & 0x70) | (val & 0xf);
272 // pclog("CRTC write R35 %02X\n", val);
273 if (svga->chain4) svga->write_bank = svga->read_bank = virge->bank << 16;
274 else svga->write_bank = svga->read_bank = virge->bank << 14;
275 break;
276 case 0x51:
277 virge->bank = (virge->bank & 0x4f) | ((val & 0xc) << 2);
278 if (svga->chain4) svga->write_bank = svga->read_bank = virge->bank << 16;
279 else svga->write_bank = svga->read_bank = virge->bank << 14;
280 virge->ma_ext = (virge->ma_ext & ~0xc) | ((val & 3) << 2);
281 break;
282 case 0x6a:
283 virge->bank = val;
284 // pclog("CRTC write R6a %02X\n", val);
285 if (svga->chain4) svga->write_bank = svga->read_bank = virge->bank << 16;
286 else svga->write_bank = svga->read_bank = virge->bank << 14;
287 break;
289 case 0x3a:
290 if (val & 0x10) svga->gdcreg[5] |= 0x40; /*Horrible cheat*/
291 break;
293 case 0x45:
294 svga->hwcursor.ena = val & 1;
295 break;
296 case 0x46: case 0x47: case 0x48: case 0x49:
297 case 0x4c: case 0x4d: case 0x4e: case 0x4f:
298 svga->hwcursor.x = ((svga->crtc[0x46] << 8) | svga->crtc[0x47]) & 0x7ff;
299 svga->hwcursor.y = ((svga->crtc[0x48] << 8) | svga->crtc[0x49]) & 0x7ff;
300 svga->hwcursor.xoff = svga->crtc[0x4e] & 63;
301 svga->hwcursor.yoff = svga->crtc[0x4f] & 63;
302 svga->hwcursor.addr = ((((svga->crtc[0x4c] << 8) | svga->crtc[0x4d]) & 0xfff) * 1024) + (svga->hwcursor.yoff * 16);
303 break;
305 case 0x53:
306 case 0x58: case 0x59: case 0x5a:
307 s3_virge_updatemapping(virge);
308 break;
310 case 0x67:
311 switch (val >> 4)
312 {
313 case 3: svga->bpp = 15; break;
314 case 5: svga->bpp = 16; break;
315 case 7: svga->bpp = 24; break;
316 case 13: svga->bpp = 32; break;
317 default: svga->bpp = 8; break;
318 }
319 break;
320 //case 0x55: case 0x43:
321 // pclog("Write CRTC R%02X %02X\n", crtcreg, val);
322 }
323 if (old != val)
324 {
325 if (svga->crtcreg < 0xe || svga->crtcreg > 0x10)
326 {
327 svga->fullchange = changeframecount;
328 svga_recalctimings(svga);
329 }
330 }
331 break;
332 }
333 svga_out(addr, val, svga);
334 }
336 static uint8_t s3_virge_in(uint16_t addr, void *p)
337 {
338 virge_t *virge = (virge_t *)p;
339 svga_t *svga = &virge->svga;
340 uint8_t ret;
342 if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1))
343 addr ^= 0x60;
345 // if (addr != 0x3da) pclog("S3 in %04X %04X:%08X ", addr, CS, pc);
346 switch (addr)
347 {
348 //case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9:
349 // pclog("Read RAMDAC %04X %04X:%04X\n", addr, CS, pc);
350 //return sdac_ramdac_in(addr);
352 case 0x3c5:
353 if (svga->seqaddr >= 0x10)
354 ret = svga->seqregs[svga->seqaddr & 0x1f];
355 else
356 ret = svga_in(addr, svga);
357 break;
359 case 0x3D4:
360 ret = svga->crtcreg;
361 break;
362 case 0x3D5:
363 //pclog("Read CRTC R%02X %04X:%04X (%02x)\n", svga->crtcreg, CS, pc, svga->crtc[svga->crtcreg]);
364 switch (svga->crtcreg)
365 {
366 case 0x2d: ret = virge->virge_id_high; break; /*Extended chip ID*/
367 case 0x2e: ret = virge->virge_id_low; break; /*New chip ID*/
368 case 0x2f: ret = virge->virge_rev; break;
369 case 0x30: ret = virge->virge_id; break; /*Chip ID*/
370 case 0x31: ret = (svga->crtc[0x31] & 0xcf) | ((virge->ma_ext & 3) << 4); break;
371 case 0x35: ret = (svga->crtc[0x35] & 0xf0) | (virge->bank & 0xf); break;
372 case 0x36: ret = (svga->crtc[0x36] & 0xfc) | 2; break; /*PCI bus*/
373 case 0x51: ret = (svga->crtc[0x51] & 0xf0) | ((virge->bank >> 2) & 0xc) | ((virge->ma_ext >> 2) & 3); break;
374 case 0x69: ret = virge->ma_ext; break;
375 case 0x6a: ret = virge->bank; break;
376 default: ret = svga->crtc[svga->crtcreg]; break;
377 }
378 break;
380 default:
381 ret = svga_in(addr, svga);
382 break;
383 }
384 // if (addr != 0x3da) pclog("%02X\n", ret);
385 return ret;
386 }
388 static void s3_virge_recalctimings(svga_t *svga)
389 {
390 virge_t *virge = (virge_t *)svga->p;
392 if (svga->crtc[0x5d] & 0x01) svga->htotal += 0x100;
393 if (svga->crtc[0x5d] & 0x02) svga->hdisp += 0x100;
394 if (svga->crtc[0x5e] & 0x01) svga->vtotal += 0x400;
395 if (svga->crtc[0x5e] & 0x02) svga->dispend += 0x400;
396 if (svga->crtc[0x5e] & 0x04) svga->vblankstart += 0x400;
397 if (svga->crtc[0x5e] & 0x10) svga->vsyncstart += 0x400;
398 if (svga->crtc[0x5e] & 0x40) svga->split += 0x400;
399 svga->interlace = svga->crtc[0x42] & 0x20;
401 if ((svga->crtc[0x67] & 0xc) != 0xc) /*VGA mode*/
402 {
403 svga->ma_latch |= (virge->ma_ext << 16);
404 //pclog("VGA mode\n");
405 if (svga->crtc[0x51] & 0x30) svga->rowoffset += (svga->crtc[0x51] & 0x30) << 4;
406 else if (svga->crtc[0x43] & 0x04) svga->rowoffset += 0x100;
407 if (!svga->rowoffset) svga->rowoffset = 256;
409 if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10))
410 {
411 switch (svga->bpp)
412 {
413 case 8:
414 svga->render = svga_render_8bpp_highres;
415 break;
416 case 15:
417 svga->render = svga_render_15bpp_highres;
418 break;
419 case 16:
420 svga->render = svga_render_16bpp_highres;
421 break;
422 case 24:
423 svga->render = svga_render_24bpp_highres;
424 break;
425 case 32:
426 svga->render = svga_render_32bpp_highres;
427 break;
428 }
429 }
431 // pclog("svga->rowoffset = %i bpp=%i\n", svga->rowoffset, svga->bpp);
432 if (svga->bpp == 15 || svga->bpp == 16)
433 {
434 svga->htotal >>= 1;
435 svga->hdisp >>= 1;
436 }
437 if (svga->bpp == 24)
438 {
439 svga->rowoffset = (svga->rowoffset * 3) / 4; /*Hack*/
440 }
441 //pclog("VGA mode x_disp=%i dispend=%i vtotal=%i\n", svga->hdisp, svga->dispend, svga->vtotal);
442 }
443 else /*Streams mode*/
444 {
445 if (virge->streams.buffer_ctrl & 1)
446 svga->ma_latch = virge->streams.pri_fb1 >> 2;
447 else
448 svga->ma_latch = virge->streams.pri_fb0 >> 2;
450 svga->hdisp = virge->streams.pri_w + 1;
451 svga->dispend = virge->streams.pri_h;
453 svga->overlay.x = virge->streams.sec_x - virge->streams.pri_x;
454 svga->overlay.y = virge->streams.sec_y - virge->streams.pri_y;
455 svga->overlay.ysize = virge->streams.sec_h;
457 if (virge->streams.buffer_ctrl & 2)
458 svga->overlay.addr = virge->streams.sec_fb1;
459 else
460 svga->overlay.addr = virge->streams.sec_fb0;
462 svga->overlay.ena = (svga->overlay.x >= 0);
463 svga->overlay.v_acc = virge->streams.dda_vert_accumulator;
464 //pclog("Streams mode x_disp=%i dispend=%i vtotal=%i x=%i y=%i ysize=%i\n", svga->hdisp, svga->dispend, svga->vtotal, svga->overlay.x, svga->overlay.y, svga->overlay.ysize);
465 svga->rowoffset = virge->streams.pri_stride >> 3;
467 switch ((virge->streams.pri_ctrl >> 24) & 0x7)
468 {
469 case 0: /*RGB-8 (CLUT)*/
470 svga->render = svga_render_8bpp_highres;
471 break;
472 case 3: /*KRGB-16 (1.5.5.5)*/
473 svga->htotal >>= 1;
474 svga->render = svga_render_15bpp_highres;
475 break;
476 case 5: /*RGB-16 (5.6.5)*/
477 svga->htotal >>= 1;
478 svga->render = svga_render_16bpp_highres;
479 break;
480 case 6: /*RGB-24 (8.8.8)*/
481 svga->render = svga_render_24bpp_highres;
482 break;
483 case 7: /*XRGB-32 (X.8.8.8)*/
484 svga->render = svga_render_32bpp_highres;
485 break;
486 }
487 }
489 if (((svga->miscout >> 2) & 3) == 3)
490 {
491 int n = svga->seqregs[0x12] & 0x1f;
492 int r = (svga->seqregs[0x12] >> 5) & 3;
493 int m = svga->seqregs[0x13] & 0x7f;
494 double freq = (((double)m + 2) / (((double)n + 2) * (double)(1 << r))) * 14318184.0;
496 svga->clock = cpuclock / freq;
497 }
498 }
500 static void s3_virge_updatemapping(virge_t *virge)
501 {
502 svga_t *svga = &virge->svga;
504 if (!(virge->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM))
505 {
506 // pclog("Update mapping - PCI disabled\n");
507 mem_mapping_disable(&svga->mapping);
508 mem_mapping_disable(&virge->linear_mapping);
509 mem_mapping_disable(&virge->mmio_mapping);
510 mem_mapping_disable(&virge->new_mmio_mapping);
511 return;
512 }
514 pclog("Update mapping - bank %02X ", svga->gdcreg[6] & 0xc);
515 switch (svga->gdcreg[6] & 0xc) /*Banked framebuffer*/
516 {
517 case 0x0: /*128k at A0000*/
518 mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000);
519 svga->banked_mask = 0xffff;
520 break;
521 case 0x4: /*64k at A0000*/
522 mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000);
523 svga->banked_mask = 0xffff;
524 break;
525 case 0x8: /*32k at B0000*/
526 mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000);
527 svga->banked_mask = 0x7fff;
528 break;
529 case 0xC: /*32k at B8000*/
530 mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000);
531 svga->banked_mask = 0x7fff;
532 break;
533 }
535 virge->linear_base = (svga->crtc[0x5a] << 16) | (svga->crtc[0x59] << 24);
537 pclog("Linear framebuffer %02X ", svga->crtc[0x58] & 0x10);
538 if (svga->crtc[0x58] & 0x10) /*Linear framebuffer*/
539 {
540 switch (svga->crtc[0x58] & 3)
541 {
542 case 0: /*64k*/
543 virge->linear_size = 0x10000;
544 break;
545 case 1: /*1mb*/
546 virge->linear_size = 0x100000;
547 break;
548 case 2: /*2mb*/
549 virge->linear_size = 0x200000;
550 break;
551 case 3: /*8mb*/
552 virge->linear_size = 0x400000;
553 break;
554 }
555 virge->linear_base &= ~(virge->linear_size - 1);
556 // pclog("%08X %08X %02X %02X %02X\n", linear_base, linear_size, crtc[0x58], crtc[0x59], crtc[0x5a]);
557 pclog("Linear framebuffer at %08X size %08X\n", virge->linear_base, virge->linear_size);
558 if (virge->linear_base == 0xa0000)
559 {
560 mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000);
561 mem_mapping_disable(&virge->linear_mapping);
562 }
563 else
564 mem_mapping_set_addr(&virge->linear_mapping, virge->linear_base, virge->linear_size);
565 }
566 else
567 mem_mapping_disable(&virge->linear_mapping);
569 pclog("Memory mapped IO %02X\n", svga->crtc[0x53] & 0x18);
570 if (svga->crtc[0x53] & 0x10) /*Old MMIO*/
571 {
572 if (svga->crtc[0x53] & 0x20)
573 mem_mapping_set_addr(&virge->mmio_mapping, 0xb8000, 0x8000);
574 else
575 mem_mapping_set_addr(&virge->mmio_mapping, 0xa0000, 0x10000);
576 }
577 else
578 mem_mapping_disable(&virge->mmio_mapping);
580 if (svga->crtc[0x53] & 0x08) /*New MMIO*/
581 mem_mapping_set_addr(&virge->new_mmio_mapping, virge->linear_base + 0x1000000, 0x10000);
582 else
583 mem_mapping_disable(&virge->new_mmio_mapping);
585 }
588 static uint8_t s3_virge_mmio_read(uint32_t addr, void *p)
589 {
590 reg_writes++;
591 // pclog("New MMIO readb %08X\n", addr);
592 switch (addr & 0xffff)
593 {
594 case 0x83b0: case 0x83b1: case 0x83b2: case 0x83b3:
595 case 0x83b4: case 0x83b5: case 0x83b6: case 0x83b7:
596 case 0x83b8: case 0x83b9: case 0x83ba: case 0x83bb:
597 case 0x83bc: case 0x83bd: case 0x83be: case 0x83bf:
598 case 0x83c0: case 0x83c1: case 0x83c2: case 0x83c3:
599 case 0x83c4: case 0x83c5: case 0x83c6: case 0x83c7:
600 case 0x83c8: case 0x83c9: case 0x83ca: case 0x83cb:
601 case 0x83cc: case 0x83cd: case 0x83ce: case 0x83cf:
602 case 0x83d0: case 0x83d1: case 0x83d2: case 0x83d3:
603 case 0x83d4: case 0x83d5: case 0x83d6: case 0x83d7:
604 case 0x83d8: case 0x83d9: case 0x83da: case 0x83db:
605 case 0x83dc: case 0x83dd: case 0x83de: case 0x83df:
606 return s3_virge_in(addr & 0x3ff, p);
607 }
608 return 0xff;
609 }
610 static uint16_t s3_virge_mmio_read_w(uint32_t addr, void *p)
611 {
612 reg_writes++;
613 // pclog("New MMIO readw %08X\n", addr);
614 switch (addr & 0xfffe)
615 {
616 default:
617 return s3_virge_mmio_read(addr, p) | (s3_virge_mmio_read(addr + 1, p) << 8);
618 }
619 return 0xffff;
620 }
621 static uint32_t s3_virge_mmio_read_l(uint32_t addr, void *p)
622 {
623 virge_t *virge = (virge_t *)p;
624 uint32_t ret = 0xffffffff;
625 reg_writes++;
626 // pclog("New MMIO readl %08X %04X(%08X):%08X ", addr, CS, cs, pc);
627 switch (addr & 0xfffc)
628 {
629 case 0x8180:
630 ret = virge->streams.pri_ctrl;
631 break;
632 case 0x8184:
633 ret = virge->streams.chroma_ctrl;
634 break;
635 case 0x8190:
636 ret = virge->streams.sec_ctrl;
637 break;
638 case 0x8194:
639 ret = virge->streams.chroma_upper_bound;
640 break;
641 case 0x8198:
642 ret = virge->streams.sec_filter;
643 break;
644 case 0x81a0:
645 ret = virge->streams.blend_ctrl;
646 break;
647 case 0x81c0:
648 ret = virge->streams.pri_fb0;
649 break;
650 case 0x81c4:
651 ret = virge->streams.pri_fb1;
652 break;
653 case 0x81c8:
654 ret = virge->streams.pri_stride;
655 break;
656 case 0x81cc:
657 ret = virge->streams.buffer_ctrl;
658 break;
659 case 0x81d0:
660 ret = virge->streams.sec_fb0;
661 break;
662 case 0x81d4:
663 ret = virge->streams.sec_fb1;
664 break;
665 case 0x81d8:
666 ret = virge->streams.sec_stride;
667 break;
668 case 0x81dc:
669 ret = virge->streams.overlay_ctrl;
670 break;
671 case 0x81e0:
672 ret = virge->streams.k1_vert_scale;
673 break;
674 case 0x81e4:
675 ret = virge->streams.k2_vert_scale;
676 break;
677 case 0x81e8:
678 ret = virge->streams.dda_vert_accumulator;
679 break;
680 case 0x81ec:
681 ret = virge->streams.fifo_ctrl;
682 break;
683 case 0x81f0:
684 ret = virge->streams.pri_start;
685 break;
686 case 0x81f4:
687 ret = virge->streams.pri_size;
688 break;
689 case 0x81f8:
690 ret = virge->streams.sec_start;
691 break;
692 case 0x81fc:
693 ret = virge->streams.sec_size;
694 break;
696 case 0x8504:
697 ret = (0x10 << 8) | (1 << 13);
698 break;
699 case 0xa4d4:
700 ret = virge->s3d.src_base;
701 break;
702 case 0xa4d8:
703 ret = virge->s3d.dest_base;
704 break;
705 case 0xa4dc:
706 ret = (virge->s3d.clip_l << 16) | virge->s3d.clip_r;
707 break;
708 case 0xa4e0:
709 ret = (virge->s3d.clip_t << 16) | virge->s3d.clip_b;
710 break;
711 case 0xa4e4:
712 ret = (virge->s3d.dest_str << 16) | virge->s3d.src_str;
713 break;
714 case 0xa4e8:
715 ret = virge->s3d.mono_pat_0;
716 break;
717 case 0xa4ec:
718 ret = virge->s3d.mono_pat_1;
719 break;
720 case 0xa4f0:
721 ret = virge->s3d.pat_bg_clr;
722 break;
723 case 0xa4f4:
724 ret = virge->s3d.pat_fg_clr;
725 break;
726 case 0xa4f8:
727 ret = virge->s3d.src_bg_clr;
728 break;
729 case 0xa4fc:
730 ret = virge->s3d.src_fg_clr;
731 break;
732 case 0xa500:
733 ret = virge->s3d.cmd_set;
734 break;
735 case 0xa504:
736 ret = (virge->s3d.r_width << 16) | virge->s3d.r_height;
737 break;
738 case 0xa508:
739 ret = (virge->s3d.rsrc_x << 16) | virge->s3d.rsrc_y;
740 break;
741 case 0xa50c:
742 ret = (virge->s3d.rdest_x << 16) | virge->s3d.rdest_y;
743 break;
745 default:
746 ret = s3_virge_mmio_read_w(addr, p) | (s3_virge_mmio_read_w(addr + 2, p) << 16);
747 }
748 // pclog("%02x\n", ret);
749 return ret;
750 }
751 static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p)
752 {
753 virge_t *virge = (virge_t *)p;
754 svga_t *svga = &virge->svga;
756 // pclog("New MMIO writeb %08X %02X %04x(%08x):%08x\n", addr, val, CS, cs, pc);
757 reg_writes++;
758 if ((addr & 0xfffc) < 0x8000)
759 s3_virge_bitblt(virge, 8, val);
760 else switch (addr & 0xffff)
761 {
762 case 0x83b0: case 0x83b1: case 0x83b2: case 0x83b3:
763 case 0x83b4: case 0x83b5: case 0x83b6: case 0x83b7:
764 case 0x83b8: case 0x83b9: case 0x83ba: case 0x83bb:
765 case 0x83bc: case 0x83bd: case 0x83be: case 0x83bf:
766 case 0x83c0: case 0x83c1: case 0x83c2: case 0x83c3:
767 case 0x83c4: case 0x83c5: case 0x83c6: case 0x83c7:
768 case 0x83c8: case 0x83c9: case 0x83ca: case 0x83cb:
769 case 0x83cc: case 0x83cd: case 0x83ce: case 0x83cf:
770 case 0x83d0: case 0x83d1: case 0x83d2: case 0x83d3:
771 case 0x83d4: case 0x83d5: case 0x83d6: case 0x83d7:
772 case 0x83d8: case 0x83d9: case 0x83da: case 0x83db:
773 case 0x83dc: case 0x83dd: case 0x83de: case 0x83df:
774 s3_virge_out(addr & 0x3ff, val, p);
775 break;
776 }
779 }
780 static void s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *p)
781 {
782 virge_t *virge = (virge_t *)p;
783 reg_writes++;
784 // pclog("New MMIO writew %08X %04X %04x(%08x):%08x\n", addr, val, CS, cs, pc);
785 if ((addr & 0xfffc) < 0x8000)
786 {
787 if (virge->s3d.cmd_set & CMD_SET_MS)
788 s3_virge_bitblt(virge, 16, ((val >> 8) | (val << 8)) << 16);
789 else
790 s3_virge_bitblt(virge, 16, val);
791 }
792 else switch (addr & 0xfffe)
793 {
794 case 0x83d4:
795 s3_virge_mmio_write(addr, val, p);
796 s3_virge_mmio_write(addr + 1, val >> 8, p);
797 break;
798 }
799 }
800 static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p)
801 {
802 virge_t *virge = (virge_t *)p;
803 svga_t *svga = &virge->svga;
804 reg_writes++;
805 // if ((addr & 0xfffc) >= 0x8000 && (addr & 0xfffc) < 0x8400)
806 // pclog("New MMIO writel %08X %08X %04x(%08x):%08x\n", addr, val, CS, cs, pc);
808 if ((addr & 0xfffc) < 0x8000)
809 {
810 if (virge->s3d.cmd_set & CMD_SET_MS)
811 s3_virge_bitblt(virge, 32, ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24));
812 else
813 s3_virge_bitblt(virge, 32, val);
814 }
815 else switch (addr & 0xfffc)
816 {
817 case 0x8180:
818 virge->streams.pri_ctrl = val;
819 s3_virge_recalctimings(svga);
820 svga->fullchange = changeframecount;
821 break;
822 case 0x8184:
823 virge->streams.chroma_ctrl = val;
824 break;
825 case 0x8190:
826 virge->streams.sec_ctrl = val;
827 virge->streams.dda_horiz_accumulator = val & 0xfff;
828 if (val & (1 << 11))
829 virge->streams.dda_horiz_accumulator |= 0xfffff800;
830 virge->streams.sdif = (val >> 24) & 7;
831 break;
832 case 0x8194:
833 virge->streams.chroma_upper_bound = val;
834 break;
835 case 0x8198:
836 virge->streams.sec_filter = val;
837 virge->streams.k1_horiz_scale = val & 0x7ff;
838 if (val & (1 << 10))
839 virge->streams.k1_horiz_scale |= 0xfffff800;
840 virge->streams.k2_horiz_scale = (val >> 16) & 0x7ff;
841 if ((val >> 16) & (1 << 10))
842 virge->streams.k2_horiz_scale |= 0xfffff800;
843 break;
844 case 0x81a0:
845 virge->streams.blend_ctrl = val;
846 break;
847 case 0x81c0:
848 virge->streams.pri_fb0 = val & 0x3fffff;
849 s3_virge_recalctimings(svga);
850 svga->fullchange = changeframecount;
851 break;
852 case 0x81c4:
853 virge->streams.pri_fb1 = val & 0x3fffff;
854 s3_virge_recalctimings(svga);
855 svga->fullchange = changeframecount;
856 break;
857 case 0x81c8:
858 virge->streams.pri_stride = val & 0xfff;
859 s3_virge_recalctimings(svga);
860 svga->fullchange = changeframecount;
861 break;
862 case 0x81cc:
863 pclog("Write buffer_ctrl %08x\n", val);
864 virge->streams.buffer_ctrl = val;
865 s3_virge_recalctimings(svga);
866 break;
867 case 0x81d0:
868 virge->streams.sec_fb0 = val;
869 s3_virge_recalctimings(svga);
870 svga->fullchange = changeframecount;
871 break;
872 case 0x81d4:
873 virge->streams.sec_fb1 = val;
874 s3_virge_recalctimings(svga);
875 svga->fullchange = changeframecount;
876 break;
877 case 0x81d8:
878 virge->streams.sec_stride = val;
879 s3_virge_recalctimings(svga);
880 svga->fullchange = changeframecount;
881 break;
882 case 0x81dc:
883 virge->streams.overlay_ctrl = val;
884 break;
885 case 0x81e0:
886 virge->streams.k1_vert_scale = val & 0x7ff;
887 if (val & (1 << 10))
888 virge->streams.k1_vert_scale |= 0xfffff800;
889 break;
890 case 0x81e4:
891 virge->streams.k2_vert_scale = val & 0x7ff;
892 if (val & (1 << 10))
893 virge->streams.k2_vert_scale |= 0xfffff800;
894 break;
895 case 0x81e8:
896 virge->streams.dda_vert_accumulator = val & 0xfff;
897 if (val & (1 << 11))
898 virge->streams.dda_vert_accumulator |= 0xfffff800;
899 break;
900 case 0x81ec:
901 virge->streams.fifo_ctrl = val;
902 break;
903 case 0x81f0:
904 virge->streams.pri_start = val;
905 virge->streams.pri_x = (val >> 16) & 0x7ff;
906 virge->streams.pri_y = val & 0x7ff;
907 s3_virge_recalctimings(svga);
908 svga->fullchange = changeframecount;
909 break;
910 case 0x81f4:
911 virge->streams.pri_size = val;
912 virge->streams.pri_w = (val >> 16) & 0x7ff;
913 virge->streams.pri_h = val & 0x7ff;
914 s3_virge_recalctimings(svga);
915 svga->fullchange = changeframecount;
916 break;
917 case 0x81f8:
918 virge->streams.sec_start = val;
919 virge->streams.sec_x = (val >> 16) & 0x7ff;
920 virge->streams.sec_y = val & 0x7ff;
921 s3_virge_recalctimings(svga);
922 svga->fullchange = changeframecount;
923 break;
924 case 0x81fc:
925 virge->streams.sec_size = val;
926 virge->streams.sec_w = (val >> 16) & 0x7ff;
927 virge->streams.sec_h = val & 0x7ff;
928 s3_virge_recalctimings(svga);
929 svga->fullchange = changeframecount;
930 break;
932 case 0xa000: case 0xa004: case 0xa008: case 0xa00c:
933 case 0xa010: case 0xa014: case 0xa018: case 0xa01c:
934 case 0xa020: case 0xa024: case 0xa028: case 0xa02c:
935 case 0xa030: case 0xa034: case 0xa038: case 0xa03c:
936 case 0xa040: case 0xa044: case 0xa048: case 0xa04c:
937 case 0xa050: case 0xa054: case 0xa058: case 0xa05c:
938 case 0xa060: case 0xa064: case 0xa068: case 0xa06c:
939 case 0xa070: case 0xa074: case 0xa078: case 0xa07c:
940 case 0xa080: case 0xa084: case 0xa088: case 0xa08c:
941 case 0xa090: case 0xa094: case 0xa098: case 0xa09c:
942 case 0xa0a0: case 0xa0a4: case 0xa0a8: case 0xa0ac:
943 case 0xa0b0: case 0xa0b4: case 0xa0b8: case 0xa0bc:
944 case 0xa0c0: case 0xa0c4: case 0xa0c8: case 0xa0cc:
945 case 0xa0d0: case 0xa0d4: case 0xa0d8: case 0xa0dc:
946 case 0xa0e0: case 0xa0e4: case 0xa0e8: case 0xa0ec:
947 case 0xa0f0: case 0xa0f4: case 0xa0f8: case 0xa0fc:
948 case 0xa100: case 0xa104: case 0xa108: case 0xa10c:
949 case 0xa110: case 0xa114: case 0xa118: case 0xa11c:
950 case 0xa120: case 0xa124: case 0xa128: case 0xa12c:
951 case 0xa130: case 0xa134: case 0xa138: case 0xa13c:
952 case 0xa140: case 0xa144: case 0xa148: case 0xa14c:
953 case 0xa150: case 0xa154: case 0xa158: case 0xa15c:
954 case 0xa160: case 0xa164: case 0xa168: case 0xa16c:
955 case 0xa170: case 0xa174: case 0xa178: case 0xa17c:
956 case 0xa180: case 0xa184: case 0xa188: case 0xa18c:
957 case 0xa190: case 0xa194: case 0xa198: case 0xa19c:
958 case 0xa1a0: case 0xa1a4: case 0xa1a8: case 0xa1ac:
959 case 0xa1b0: case 0xa1b4: case 0xa1b8: case 0xa1bc:
960 case 0xa1c0: case 0xa1c4: case 0xa1c8: case 0xa1cc:
961 case 0xa1d0: case 0xa1d4: case 0xa1d8: case 0xa1dc:
962 case 0xa1e0: case 0xa1e4: case 0xa1e8: case 0xa1ec:
963 case 0xa1f0: case 0xa1f4: case 0xa1f8: case 0xa1fc:
964 {
965 int x = addr & 4;
966 int y = (addr >> 3) & 7;
967 virge->s3d.pattern_8[y*8 + x] = val & 0xff;
968 virge->s3d.pattern_8[y*8 + x + 1] = val >> 8;
969 virge->s3d.pattern_8[y*8 + x + 2] = val >> 16;
970 virge->s3d.pattern_8[y*8 + x + 3] = val >> 24;
972 x = (addr >> 1) & 6;
973 y = (addr >> 4) & 7;
974 virge->s3d.pattern_16[y*8 + x] = val & 0xffff;
975 virge->s3d.pattern_16[y*8 + x + 1] = val >> 16;
977 x = (addr >> 2) & 7;
978 y = (addr >> 5) & 7;
979 virge->s3d.pattern_32[y*8 + x] = val & 0xffffff;
980 }
981 break;
984 case 0xa4d4: case 0xa8d4:
985 virge->s3d.src_base = val & 0x3ffff8;
986 break;
987 case 0xa4d8: case 0xa8d8: case 0xb4d8:
988 virge->s3d.dest_base = val & 0x3ffff8;
989 break;
990 case 0xa4dc: case 0xa8dc: case 0xb4dc:
991 virge->s3d.clip_l = (val >> 16) & 0x7ff;
992 virge->s3d.clip_r = val & 0x7ff;
993 break;
994 case 0xa4e0: case 0xa8e0: case 0xb4e0:
995 virge->s3d.clip_t = (val >> 16) & 0x7ff;
996 virge->s3d.clip_b = val & 0x7ff;
997 break;
998 case 0xa4e4: case 0xa8e4: case 0xb4e4:
999 virge->s3d.dest_str = (val >> 16) & 0xff8;
1000 virge->s3d.src_str = val & 0xff8;
1001 break;
1002 case 0xa4e8:
1003 virge->s3d.mono_pat_0 = val;
1004 break;
1005 case 0xa4ec:
1006 virge->s3d.mono_pat_1 = val;
1007 break;
1008 case 0xa4f0:
1009 virge->s3d.pat_bg_clr = val;
1010 break;
1011 case 0xa4f4: case 0xa8f4:
1012 virge->s3d.pat_fg_clr = val;
1013 break;
1014 case 0xa4f8:
1015 virge->s3d.src_bg_clr = val;
1016 break;
1017 case 0xa4fc:
1018 virge->s3d.src_fg_clr = val;
1019 break;
1020 case 0xa500: case 0xa900:
1021 virge->s3d.cmd_set = val;
1022 if (!(val & CMD_SET_AE))
1023 s3_virge_bitblt(virge, -1, 0);
1024 break;
1025 case 0xa504:
1026 virge->s3d.r_width = (val >> 16) & 0x7ff;
1027 virge->s3d.r_height = val & 0x7ff;
1028 break;
1029 case 0xa508:
1030 virge->s3d.rsrc_x = (val >> 16) & 0x7ff;
1031 virge->s3d.rsrc_y = val & 0x7ff;
1032 break;
1033 case 0xa50c:
1034 virge->s3d.rdest_x = (val >> 16) & 0x7ff;
1035 virge->s3d.rdest_y = val & 0x7ff;
1036 if (virge->s3d.cmd_set & CMD_SET_AE)
1037 s3_virge_bitblt(virge, -1, 0);
1038 break;
1039 case 0xa96c:
1040 virge->s3d.lxend0 = (val >> 16) & 0x7ff;
1041 virge->s3d.lxend1 = val & 0x7ff;
1042 break;
1043 case 0xa970:
1044 virge->s3d.ldx = (int32_t)val;
1045 break;
1046 case 0xa974:
1047 virge->s3d.lxstart = val;
1048 break;
1049 case 0xa978:
1050 virge->s3d.lystart = val & 0x7ff;
1051 break;
1052 case 0xa97c:
1053 virge->s3d.lycnt = val & 0x7ff;
1054 virge->s3d.line_dir = val >> 31;
1055 if (virge->s3d.cmd_set & CMD_SET_AE)
1056 s3_virge_bitblt(virge, -1, 0);
1057 break;
1059 case 0xb4d4:
1060 virge->s3d.z_base = val & 0x3ffff8;
1061 break;
1062 case 0xb4e8:
1063 virge->s3d.z_str = val & 0xff8;
1064 break;
1065 case 0xb4ec:
1066 virge->s3d.tex_base = val & 0x3ffff8;
1067 break;
1068 case 0xb4f0:
1069 virge->s3d.tex_bdr_clr = val & 0xffffff;
1070 break;
1071 case 0xb500:
1072 virge->s3d.cmd_set = val;
1073 if (!(val & CMD_SET_AE))
1074 s3_virge_triangle(virge);
1075 break;
1076 case 0xb504:
1077 virge->s3d.tbv = val & 0xfffff;
1078 break;
1079 case 0xb508:
1080 virge->s3d.tbu = val & 0xfffff;
1081 break;
1082 case 0xb50c:
1083 virge->s3d.TdWdX = val;
1084 break;
1085 case 0xb510:
1086 virge->s3d.TdWdY = val;
1087 break;
1088 case 0xb514:
1089 virge->s3d.tws = val;
1090 break;
1091 case 0xb518:
1092 virge->s3d.TdDdX = val;
1093 break;
1094 case 0xb51c:
1095 virge->s3d.TdVdX = val;
1096 break;
1097 case 0xb520:
1098 virge->s3d.TdUdX = val;
1099 break;
1100 case 0xb524:
1101 virge->s3d.TdDdY = val;
1102 break;
1103 case 0xb528:
1104 virge->s3d.TdVdY = val;
1105 break;
1106 case 0xb52c:
1107 virge->s3d.TdUdY = val;
1108 break;
1109 case 0xb530:
1110 virge->s3d.tds = val;
1111 break;
1112 case 0xb534:
1113 virge->s3d.tvs = val;
1114 break;
1115 case 0xb538:
1116 virge->s3d.tus = val;
1117 break;
1118 case 0xb53c:
1119 virge->s3d.TdGdX = val >> 16;
1120 virge->s3d.TdBdX = val & 0xffff;
1121 break;
1122 case 0xb540:
1123 virge->s3d.TdAdX = val >> 16;
1124 virge->s3d.TdRdX = val & 0xffff;
1125 break;
1126 case 0xb544:
1127 virge->s3d.TdGdY = val >> 16;
1128 virge->s3d.TdBdY = val & 0xffff;
1129 break;
1130 case 0xb548:
1131 virge->s3d.TdAdY = val >> 16;
1132 virge->s3d.TdRdY = val & 0xffff;
1133 break;
1134 case 0xb54c:
1135 virge->s3d.tgs = (val >> 16) & 0xffff;
1136 virge->s3d.tbs = val & 0xffff;
1137 break;
1138 case 0xb550:
1139 virge->s3d.tas = (val >> 16) & 0xffff;
1140 virge->s3d.trs = val & 0xffff;
1141 break;
1143 case 0xb554:
1144 virge->s3d.TdZdX = val;
1145 break;
1146 case 0xb558:
1147 virge->s3d.TdZdY = val;
1148 break;
1149 case 0xb55c:
1150 virge->s3d.tzs = val;
1151 break;
1152 case 0xb560:
1153 virge->s3d.TdXdY12 = val;
1154 break;
1155 case 0xb564:
1156 virge->s3d.txend12 = val;
1157 break;
1158 case 0xb568:
1159 virge->s3d.TdXdY01 = val;
1160 break;
1161 case 0xb56c:
1162 virge->s3d.txend01 = val;
1163 break;
1164 case 0xb570:
1165 virge->s3d.TdXdY02 = val;
1166 break;
1167 case 0xb574:
1168 virge->s3d.txs = val;
1169 break;
1170 case 0xb578:
1171 virge->s3d.tys = val;
1172 break;
1173 case 0xb57c:
1174 virge->s3d.ty01 = (val >> 16) & 0x7ff;
1175 virge->s3d.ty12 = val & 0x7ff;
1176 virge->s3d.tlr = val >> 31;
1177 if (virge->s3d.cmd_set & CMD_SET_AE)
1178 s3_virge_triangle(virge);
1179 break;
1180 }
1181 }
1183 #define READ(addr, val) \
1184 do \
1185 { \
1186 switch (bpp) \
1187 { \
1188 case 0: /*8 bpp*/ \
1189 val = vram[addr & 0x3fffff]; \
1190 break; \
1191 case 1: /*16 bpp*/ \
1192 val = *(uint16_t *)&vram[addr & 0x3fffff]; \
1193 break; \
1194 case 2: /*24 bpp*/ \
1195 val = (*(uint32_t *)&vram[addr & 0x3fffff]) & 0xffffff; \
1196 break; \
1197 } \
1198 } while (0)
1200 #define Z_READ(addr) *(uint16_t *)&vram[addr & 0x3fffff]
1202 #define Z_WRITE(addr, val) if (!(virge->s3d.cmd_set & CMD_SET_ZB_MODE)) *(uint16_t *)&vram[addr & 0x3fffff] = val
1204 #define CLIP(x, y) \
1205 do \
1206 { \
1207 if ((virge->s3d.cmd_set & CMD_SET_HC) && \
1208 (x < virge->s3d.clip_l || \
1209 x > virge->s3d.clip_r || \
1210 y < virge->s3d.clip_t || \
1211 y > virge->s3d.clip_b)) \
1212 update = 0; \
1213 } while (0)
1215 #define Z_CLIP(Zzb, Zs) \
1216 do \
1217 { \
1218 if (!(virge->s3d.cmd_set & CMD_SET_ZB_MODE)) \
1219 switch ((virge->s3d.cmd_set >> 20) & 7) \
1220 { \
1221 case 0: update = 0; break; \
1222 case 1: if (Zs <= Zzb) update = 0; else Zzb = Zs; break; \
1223 case 2: if (Zs != Zzb) update = 0; else Zzb = Zs; break; \
1224 case 3: if (Zs < Zzb) update = 0; else Zzb = Zs; break; \
1225 case 4: if (Zs >= Zzb) update = 0; else Zzb = Zs; break; \
1226 case 5: if (Zs == Zzb) update = 0; else Zzb = Zs; break; \
1227 case 6: if (Zs > Zzb) update = 0; else Zzb = Zs; break; \
1228 case 7: update = 1; Zzb = Zs; break; \
1229 } \
1230 } while (0)
1232 #define MIX() \
1233 do \
1234 { \
1235 int c; \
1236 for (c = 0; c < 24; c++) \
1237 { \
1238 int d = (dest & (1 << c)) ? 1 : 0; \
1239 if (source & (1 << c)) d |= 2; \
1240 if (pattern & (1 << c)) d |= 4; \
1241 if (virge->s3d.rop & (1 << d)) out |= (1 << c); \
1242 } \
1243 } while (0)
1245 #define WRITE(addr, val) \
1246 do \
1247 { \
1248 switch (bpp) \
1249 { \
1250 case 0: /*8 bpp*/ \
1251 vram[addr & 0x3fffff] = val; \
1252 virge->svga.changedvram[(addr & 0x3fffff) >> 12] = changeframecount; \
1253 break; \
1254 case 1: /*16 bpp*/ \
1255 *(uint16_t *)&vram[addr & 0x3fffff] = val; \
1256 virge->svga.changedvram[(addr & 0x3fffff) >> 12] = changeframecount; \
1257 break; \
1258 case 2: /*24 bpp*/ \
1259 *(uint32_t *)&vram[addr & 0x3fffff] = (val & 0xffffff) | \
1260 (vram[(addr + 3) & 0x3fffff] << 24); \
1261 virge->svga.changedvram[(addr & 0x3fffff) >> 12] = changeframecount; \
1262 break; \
1263 } \
1264 } while (0)
1266 static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat)
1267 {
1268 int cpu_input = (count != -1);
1269 uint8_t *vram = virge->svga.vram;
1270 uint32_t mono_pattern[64];
1271 int count_mask;
1272 int x_inc = (virge->s3d.cmd_set & CMD_SET_XP) ? 1 : -1;
1273 int y_inc = (virge->s3d.cmd_set & CMD_SET_YP) ? 1 : -1;
1274 int bpp;
1275 int x_mul;
1276 int cpu_dat_shift;
1277 uint32_t *pattern_data;
1279 switch (virge->s3d.cmd_set & CMD_SET_FORMAT_MASK)
1280 {
1281 case CMD_SET_FORMAT_8:
1282 bpp = 0;
1283 x_mul = 1;
1284 cpu_dat_shift = 8;
1285 pattern_data = virge->s3d.pattern_8;
1286 break;
1287 case CMD_SET_FORMAT_16:
1288 bpp = 1;
1289 x_mul = 2;
1290 cpu_dat_shift = 16;
1291 pattern_data = virge->s3d.pattern_16;
1292 break;
1293 case CMD_SET_FORMAT_24:
1294 default:
1295 bpp = 2;
1296 x_mul = 3;
1297 cpu_dat_shift = 24;
1298 pattern_data = virge->s3d.pattern_32;
1299 break;
1300 }
1301 if (virge->s3d.cmd_set & CMD_SET_MP)
1302 pattern_data = mono_pattern;
1304 switch (virge->s3d.cmd_set & CMD_SET_ITA_MASK)
1305 {
1306 case CMD_SET_ITA_BYTE:
1307 count_mask = ~0x7;
1308 break;
1309 case CMD_SET_ITA_WORD:
1310 count_mask = ~0xf;
1311 break;
1312 case CMD_SET_ITA_DWORD:
1313 default:
1314 count_mask = ~0x1f;
1315 break;
1316 }
1317 if (virge->s3d.cmd_set & CMD_SET_MP)
1318 {
1319 int x, y;
1320 for (y = 0; y < 4; y++)
1321 {
1322 for (x = 0; x < 8; x++)
1323 {
1324 if (virge->s3d.mono_pat_0 & (1 << (x + y*8)))
1325 mono_pattern[y*8 + x] = virge->s3d.pat_fg_clr;
1326 else
1327 mono_pattern[y*8 + x] = virge->s3d.pat_bg_clr;
1328 if (virge->s3d.mono_pat_1 & (1 << (x + y*8)))
1329 mono_pattern[(y+4)*8 + x] = virge->s3d.pat_fg_clr;
1330 else
1331 mono_pattern[(y+4)*8 + x] = virge->s3d.pat_bg_clr;
1332 }
1333 }
1334 }
1335 switch (virge->s3d.cmd_set & CMD_SET_COMMAND_MASK)
1336 {
1337 case CMD_SET_COMMAND_NOP:
1338 break;
1340 case CMD_SET_COMMAND_BITBLT:
1341 if (count == -1)
1342 {
1343 virge->s3d.src_x = virge->s3d.rsrc_x;
1344 virge->s3d.src_y = virge->s3d.rsrc_y;
1345 virge->s3d.dest_x = virge->s3d.rdest_x;
1346 virge->s3d.dest_y = virge->s3d.rdest_y;
1347 virge->s3d.w = virge->s3d.r_width;
1348 virge->s3d.h = virge->s3d.r_height;
1349 virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff;
1350 virge->s3d.data_left_count = 0;
1352 /* pclog("BitBlt start %i,%i %i,%i %i,%i %02X %x %x\n",
1353 virge->s3d.src_x,
1354 virge->s3d.src_y,
1355 virge->s3d.dest_x,
1356 virge->s3d.dest_y,
1357 virge->s3d.w,
1358 virge->s3d.h,
1359 virge->s3d.rop,
1360 virge->s3d.src_base,
1361 virge->s3d.dest_base);*/
1363 if (virge->s3d.cmd_set & CMD_SET_IDS)
1364 return;
1365 }
1366 if (!virge->s3d.h)
1367 return;
1368 while (count)
1369 {
1370 uint32_t src_addr = virge->s3d.src_base + (virge->s3d.src_x * x_mul) + (virge->s3d.src_y * virge->s3d.src_str);
1371 uint32_t dest_addr = virge->s3d.dest_base + (virge->s3d.dest_x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str);
1372 uint32_t source, dest, pattern;
1373 uint32_t out = 0;
1374 int update = 1;
1376 switch (virge->s3d.cmd_set & (CMD_SET_MS | CMD_SET_IDS))
1377 {
1378 case 0:
1379 case CMD_SET_MS:
1380 READ(src_addr, source);
1381 if ((virge->s3d.cmd_set & CMD_SET_TP) && source == virge->s3d.src_fg_clr)
1382 update = 0;
1383 break;
1384 case CMD_SET_IDS:
1385 if (virge->s3d.data_left_count)
1386 {
1387 /*Handle shifting for 24-bit data*/
1388 source = virge->s3d.data_left;
1389 source |= ((cpu_dat << virge->s3d.data_left_count) & ~0xff000000);
1390 cpu_dat >>= (cpu_dat_shift - virge->s3d.data_left_count);
1391 count -= (cpu_dat_shift - virge->s3d.data_left_count);
1392 virge->s3d.data_left_count = 0;
1393 if (count < cpu_dat_shift)
1394 {
1395 virge->s3d.data_left = cpu_dat;
1396 virge->s3d.data_left_count = count;
1397 count = 0;
1398 }
1399 }
1400 else
1401 {
1402 source = cpu_dat;
1403 cpu_dat >>= cpu_dat_shift;
1404 count -= cpu_dat_shift;
1405 if (count < cpu_dat_shift)
1406 {
1407 virge->s3d.data_left = cpu_dat;
1408 virge->s3d.data_left_count = count;
1409 count = 0;
1410 }
1411 }
1412 if ((virge->s3d.cmd_set & CMD_SET_TP) && source == virge->s3d.src_fg_clr)
1413 update = 0;
1414 break;
1415 case CMD_SET_IDS | CMD_SET_MS:
1416 source = (cpu_dat & (1 << 31)) ? virge->s3d.src_fg_clr : virge->s3d.src_bg_clr;
1417 if ((virge->s3d.cmd_set & CMD_SET_TP) && !(cpu_dat & (1 << 31)))
1418 update = 0;
1419 cpu_dat <<= 1;
1420 count--;
1421 break;
1422 }
1424 CLIP(virge->s3d.dest_x, virge->s3d.dest_y);
1426 if (update)
1427 {
1428 READ(dest_addr, dest);
1429 pattern = pattern_data[(virge->s3d.dest_y & 7)*8 + (virge->s3d.dest_x & 7)];
1430 MIX();
1432 WRITE(dest_addr, out);
1433 }
1435 virge->s3d.src_x += x_inc;
1436 virge->s3d.dest_x += x_inc;
1437 if (!virge->s3d.w)
1438 {
1439 virge->s3d.src_x = virge->s3d.rsrc_x;
1440 virge->s3d.dest_x = virge->s3d.rdest_x;
1441 virge->s3d.w = virge->s3d.r_width;
1443 virge->s3d.src_y += y_inc;
1444 virge->s3d.dest_y += y_inc;
1445 virge->s3d.h--;
1447 switch (virge->s3d.cmd_set & (CMD_SET_MS | CMD_SET_IDS))
1448 {
1449 case CMD_SET_IDS:
1450 cpu_dat >>= (count - (count & count_mask));
1451 count &= count_mask;
1452 virge->s3d.data_left_count = 0;
1453 break;
1455 case CMD_SET_IDS | CMD_SET_MS:
1456 cpu_dat <<= (count - (count & count_mask));
1457 count &= count_mask;
1458 break;
1459 }
1460 if (!virge->s3d.h)
1461 {
1462 return;
1463 }
1464 }
1465 else
1466 virge->s3d.w--;
1467 }
1468 break;
1470 case CMD_SET_COMMAND_RECTFILL:
1471 /*No source, pattern = pat_fg_clr*/
1472 if (count == -1)
1473 {
1474 virge->s3d.src_x = virge->s3d.rsrc_x;
1475 virge->s3d.src_y = virge->s3d.rsrc_y;
1476 virge->s3d.dest_x = virge->s3d.rdest_x;
1477 virge->s3d.dest_y = virge->s3d.rdest_y;
1478 virge->s3d.w = virge->s3d.r_width;
1479 virge->s3d.h = virge->s3d.r_height;
1480 virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff;
1482 /* pclog("RctFll start %i,%i %i,%i %02X %08x\n", virge->s3d.dest_x,
1483 virge->s3d.dest_y,
1484 virge->s3d.w,
1485 virge->s3d.h,
1486 virge->s3d.rop, virge->s3d.dest_base);*/
1487 }
1489 while (count)
1490 {
1491 uint32_t dest_addr = virge->s3d.dest_base + (virge->s3d.dest_x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str);
1492 uint32_t source = 0, dest, pattern = virge->s3d.pat_fg_clr;
1493 uint32_t out = 0;
1494 int update = 1;
1496 CLIP(virge->s3d.dest_x, virge->s3d.dest_y);
1498 if (update)
1499 {
1500 READ(dest_addr, dest);
1502 MIX();
1504 WRITE(dest_addr, out);
1505 }
1507 virge->s3d.src_x += x_inc;
1508 virge->s3d.dest_x += x_inc;
1509 if (!virge->s3d.w)
1510 {
1511 virge->s3d.src_x = virge->s3d.rsrc_x;
1512 virge->s3d.dest_x = virge->s3d.rdest_x;
1513 virge->s3d.w = virge->s3d.r_width;
1515 virge->s3d.src_y += y_inc;
1516 virge->s3d.dest_y += y_inc;
1517 virge->s3d.h--;
1518 if (!virge->s3d.h)
1519 {
1520 return;
1521 }
1522 }
1523 else
1524 virge->s3d.w--;
1525 count--;
1526 }
1527 break;
1529 case CMD_SET_COMMAND_LINE:
1530 if (count == -1)
1531 {
1532 virge->s3d.dest_x = virge->s3d.lxstart;
1533 virge->s3d.dest_y = virge->s3d.lystart;
1534 virge->s3d.h = virge->s3d.lycnt;
1535 virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff;
1536 if (virge->s3d.ldx >= 0)
1537 virge->s3d.dest_x -= virge->s3d.ldx / 2;
1538 else
1539 virge->s3d.dest_x += virge->s3d.ldx / 2;
1540 //virge->s3d.dest_dest_x = virge->s3d.dest_x + virge->s3d.ldx;
1541 }
1542 while (virge->s3d.h)
1543 {
1544 int x = virge->s3d.dest_x >> 20;
1545 int new_x = (virge->s3d.dest_x + virge->s3d.ldx) >> 20;
1547 do
1548 {
1549 uint32_t dest_addr = virge->s3d.dest_base + (x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str);
1550 uint32_t source = 0, dest, pattern;
1551 uint32_t out = 0;
1552 int update = 1;
1554 CLIP(x, virge->s3d.dest_y);
1556 if (update)
1557 {
1558 READ(dest_addr, dest);
1559 pattern = virge->s3d.pat_fg_clr;
1561 MIX();
1563 WRITE(dest_addr, out);
1564 }
1566 if (x < new_x)
1567 x++;
1568 else if (x > new_x)
1569 x--;
1570 } while (x != new_x);
1572 virge->s3d.dest_x += virge->s3d.ldx;
1573 virge->s3d.dest_y--;
1574 virge->s3d.h--;
1575 }
1576 break;
1578 default:
1579 fatal("s3_virge_bitblt : blit command %i %08x\n", (virge->s3d.cmd_set >> 27) & 0xf, virge->s3d.cmd_set);
1580 }
1581 }
1583 #define RGB15_TO_24(val, r, g, b) b = (val & 0x1f) << 3; \
1584 g = (val & 0x3e0) >> 2; \
1585 r = (val & 0x7c00) >> 7
1587 #define RGB24_TO_24(val, r, g, b) b = val & 0xff; \
1588 g = (val & 0xff00) >> 8; \
1589 r = (val & 0xff0000) >> 16
1591 #define RGB15(r, g, b) ((((b) >> 3) & 0x1f) | ((((g) >> 3) & 0x1f) << 5) | ((((r) >> 3) & 0x1f) << 10))
1593 #define RGB24(r, g, b) ((b) | ((g) << 8) | ((r) << 16))
1595 typedef struct rgba_t
1596 {
1597 int r, g, b, a;
1598 } rgba_t;
1600 typedef struct s3d_state_t
1601 {
1602 int32_t r, g, b, a, u, v, d, w;
1604 int32_t base_r, base_g, base_b, base_a, base_u, base_v, base_d, base_w;
1606 uint32_t base_z;
1608 uint32_t tbu, tbv;
1610 uint32_t cmd_set;
1611 int max_d;
1613 uint16_t *texture[10];
1615 uint32_t tex_bdr_clr;
1617 int32_t x1, x2;
1618 int y;
1620 rgba_t dest_rgba;
1621 } s3d_state_t;
1623 typedef struct s3d_texture_state_t
1624 {
1625 int level;
1626 int texture_shift;
1628 int32_t u, v;
1629 } s3d_texture_state_t;
1631 static void (*tex_read)(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out);
1632 static void (*tex_sample)(s3d_state_t *state);
1633 static void (*dest_pixel)(s3d_state_t *state);
1635 #define MAX(a, b) ((a) > (b) ? (a) : (b))
1636 #define MIN(a, b) ((a) < (b) ? (a) : (b))
1638 static int _x, _y;
1640 static void tex_ARGB1555(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out)
1641 {
1642 int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) +
1643 (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level);
1644 uint16_t val = state->texture[texture_state->level][offset];
1646 out->r = ((val & 0x7c00) >> 7) | ((val & 0x7000) >> 12);
1647 out->g = ((val & 0x03e0) >> 2) | ((val & 0x0380) >> 7);
1648 out->b = ((val & 0x001f) << 3) | ((val & 0x001c) >> 2);
1649 out->a = (val & 0x8000) ? 0xff : 0;
1650 }
1652 static void tex_ARGB1555_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out)
1653 {
1654 int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) +
1655 (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level);
1656 uint16_t val = state->texture[texture_state->level][offset];
1658 if (((texture_state->u | texture_state->v) & 0xf8000000) == 0xf8000000)
1659 val = state->tex_bdr_clr;
1661 out->r = ((val & 0x7c00) >> 7) | ((val & 0x7000) >> 12);
1662 out->g = ((val & 0x03e0) >> 2) | ((val & 0x0380) >> 7);
1663 out->b = ((val & 0x001f) << 3) | ((val & 0x001c) >> 2);
1664 out->a = (val & 0x8000) ? 0xff : 0;
1665 }
1667 static void tex_ARGB4444(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out)
1668 {
1669 int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) +
1670 (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level);
1671 uint16_t val = state->texture[texture_state->level][offset];
1673 out->r = ((val & 0x0f00) >> 4) | ((val & 0x0f00) >> 8);
1674 out->g = (val & 0x00f0) | ((val & 0x00f0) >> 4);
1675 out->b = ((val & 0x000f) << 4) | (val & 0x000f);
1676 out->a = ((val & 0xf000) >> 8) | ((val & 0xf000) >> 12);
1677 }
1679 static void tex_ARGB4444_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out)
1680 {
1681 int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) +
1682 (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level);
1683 uint16_t val = state->texture[texture_state->level][offset];
1685 if (((texture_state->u | texture_state->v) & 0xf8000000) == 0xf8000000)
1686 val = state->tex_bdr_clr;
1688 out->r = ((val & 0x0f00) >> 4) | ((val & 0x0f00) >> 8);
1689 out->g = (val & 0x00f0) | ((val & 0x00f0) >> 4);
1690 out->b = ((val & 0x000f) << 4) | (val & 0x000f);
1691 out->a = ((val & 0xf000) >> 8) | ((val & 0xf000) >> 12);
1692 }
1694 static void tex_ARGB8888(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out)
1695 {
1696 int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) +
1697 (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level);
1698 uint32_t val = ((uint32_t *)state->texture[texture_state->level])[offset];
1700 out->r = (val >> 16) & 0xff;
1701 out->g = (val >> 8) & 0xff;
1702 out->b = val & 0xff;
1703 out->a = (val >> 24) & 0xff;
1704 }
1705 static void tex_ARGB8888_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out)
1706 {
1707 int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) +
1708 (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level);
1709 uint32_t val = ((uint32_t *)state->texture[texture_state->level])[offset];
1711 if (((texture_state->u | texture_state->v) & 0xf8000000) == 0xf8000000)
1712 val = state->tex_bdr_clr;
1714 out->r = (val >> 16) & 0xff;
1715 out->g = (val >> 8) & 0xff;
1716 out->b = val & 0xff;
1717 out->a = (val >> 24) & 0xff;
1718 }
1720 static void tex_sample_normal(s3d_state_t *state)
1721 {
1722 s3d_texture_state_t texture_state;
1724 texture_state.level = state->max_d;
1725 texture_state.texture_shift = 18 + (9 - texture_state.level);
1726 texture_state.u = state->u + state->tbu;
1727 texture_state.v = state->v + state->tbv;
1729 tex_read(state, &texture_state, &state->dest_rgba);
1730 }
1732 static void tex_sample_normal_filter(s3d_state_t *state)
1733 {
1734 s3d_texture_state_t texture_state;
1735 int tex_offset;
1736 rgba_t tex_samples[4];
1737 int du, dv;
1738 int d[4];
1740 texture_state.level = state->max_d;
1741 texture_state.texture_shift = 18 + (9 - texture_state.level);
1742 tex_offset = 1 << texture_state.texture_shift;
1744 texture_state.u = state->u + state->tbu;
1745 texture_state.v = state->v + state->tbv;
1746 tex_read(state, &texture_state, &tex_samples[0]);
1747 du = (texture_state.u >> (texture_state.texture_shift - 8)) & 0xff;
1748 dv = (texture_state.v >> (texture_state.texture_shift - 8)) & 0xff;
1750 texture_state.u = state->u + state->tbu + tex_offset;
1751 texture_state.v = state->v + state->tbv;
1752 tex_read(state, &texture_state, &tex_samples[1]);
1754 texture_state.u = state->u + state->tbu;
1755 texture_state.v = state->v + state->tbv + tex_offset;
1756 tex_read(state, &texture_state, &tex_samples[2]);
1758 texture_state.u = state->u + state->tbu + tex_offset;
1759 texture_state.v = state->v + state->tbv + tex_offset;
1760 tex_read(state, &texture_state, &tex_samples[3]);
1762 d[0] = (256 - du) * (256 - dv);
1763 d[1] = du * (256 - dv);
1764 d[2] = (256 - du) * dv;
1765 d[3] = du * dv;
1767 state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16;
1768 state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16;
1769 state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16;
1770 state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16;
1771 }
1773 static void tex_sample_mipmap(s3d_state_t *state)
1774 {
1775 s3d_texture_state_t texture_state;
1777 texture_state.level = MAX(MIN(9 - ((state->d >> 27) & 0xf), state->max_d), 0);
1778 texture_state.texture_shift = 18 + (9 - texture_state.level);
1779 texture_state.u = state->u + state->tbu;
1780 texture_state.v = state->v + state->tbv;
1782 tex_read(state, &texture_state, &state->dest_rgba);
1783 }
1785 static void tex_sample_mipmap_filter(s3d_state_t *state)
1786 {
1787 s3d_texture_state_t texture_state;
1788 int tex_offset;
1789 rgba_t tex_samples[4];
1790 int du, dv;
1791 int d[4];
1793 texture_state.level = MAX(MIN(9 - ((state->d >> 27) & 0xf), state->max_d), 0);
1794 texture_state.texture_shift = 18 + (9 - texture_state.level);
1795 tex_offset = 1 << texture_state.texture_shift;
1797 texture_state.u = state->u + state->tbu;
1798 texture_state.v = state->v + state->tbv;
1799 tex_read(state, &texture_state, &tex_samples[0]);
1800 du = (texture_state.u >> (texture_state.texture_shift - 8)) & 0xff;
1801 dv = (texture_state.v >> (texture_state.texture_shift - 8)) & 0xff;
1803 texture_state.u = state->u + state->tbu + tex_offset;
1804 texture_state.v = state->v + state->tbv;
1805 tex_read(state, &texture_state, &tex_samples[1]);
1807 texture_state.u = state->u + state->tbu;
1808 texture_state.v = state->v + state->tbv + tex_offset;
1809 tex_read(state, &texture_state, &tex_samples[2]);
1811 texture_state.u = state->u + state->tbu + tex_offset;
1812 texture_state.v = state->v + state->tbv + tex_offset;
1813 tex_read(state, &texture_state, &tex_samples[3]);
1815 d[0] = (256 - du) * (256 - dv);
1816 d[1] = du * (256 - dv);
1817 d[2] = (256 - du) * dv;
1818 d[3] = du * dv;
1820 state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16;
1821 state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16;
1822 state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16;
1823 state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16;
1824 }
1826 static void tex_sample_persp_normal(s3d_state_t *state)
1827 {
1828 s3d_texture_state_t texture_state;
1829 int32_t w = 0;
1831 if (state->w)
1832 w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w);
1834 texture_state.level = state->max_d;
1835 texture_state.texture_shift = 18 + (9 - texture_state.level);
1836 texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu;
1837 texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv;
1839 tex_read(state, &texture_state, &state->dest_rgba);
1840 }
1842 static void tex_sample_persp_normal_filter(s3d_state_t *state)
1843 {
1844 s3d_texture_state_t texture_state;
1845 int32_t w = 0, u, v;
1846 int tex_offset;
1847 rgba_t tex_samples[4];
1848 int du, dv;
1849 int d[4];
1851 if (state->w)
1852 w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w);
1854 u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu;
1855 v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv;
1857 texture_state.level = state->max_d;
1858 texture_state.texture_shift = 18 + (9 - texture_state.level);
1859 tex_offset = 1 << texture_state.texture_shift;
1861 texture_state.u = u;
1862 texture_state.v = v;
1863 tex_read(state, &texture_state, &tex_samples[0]);
1864 du = (u >> (texture_state.texture_shift - 8)) & 0xff;
1865 dv = (v >> (texture_state.texture_shift - 8)) & 0xff;
1867 texture_state.u = u + tex_offset;
1868 texture_state.v = v;
1869 tex_read(state, &texture_state, &tex_samples[1]);
1871 texture_state.u = u;
1872 texture_state.v = v + tex_offset;
1873 tex_read(state, &texture_state, &tex_samples[2]);
1875 texture_state.u = u + tex_offset;
1876 texture_state.v = v + tex_offset;
1877 tex_read(state, &texture_state, &tex_samples[3]);
1879 d[0] = (256 - du) * (256 - dv);
1880 d[1] = du * (256 - dv);
1881 d[2] = (256 - du) * dv;
1882 d[3] = du * dv;
1884 state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16;
1885 state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16;
1886 state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16;
1887 state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16;
1888 }
1890 static void tex_sample_persp_normal_375(s3d_state_t *state)
1891 {
1892 s3d_texture_state_t texture_state;
1893 int32_t w = 0;
1895 if (state->w)
1896 w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w);
1898 texture_state.level = state->max_d;
1899 texture_state.texture_shift = 18 + (9 - texture_state.level);
1900 texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu;
1901 texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv;
1903 tex_read(state, &texture_state, &state->dest_rgba);
1904 }
1906 static void tex_sample_persp_normal_filter_375(s3d_state_t *state)
1907 {
1908 s3d_texture_state_t texture_state;
1909 int32_t w = 0, u, v;
1910 int tex_offset;
1911 rgba_t tex_samples[4];
1912 int du, dv;
1913 int d[4];
1915 if (state->w)
1916 w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w);
1918 u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu;
1919 v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv;
1921 texture_state.level = state->max_d;
1922 texture_state.texture_shift = 18 + (9 - texture_state.level);
1923 tex_offset = 1 << texture_state.texture_shift;
1925 texture_state.u = u;
1926 texture_state.v = v;
1927 tex_read(state, &texture_state, &tex_samples[0]);
1928 du = (u >> (texture_state.texture_shift - 8)) & 0xff;
1929 dv = (v >> (texture_state.texture_shift - 8)) & 0xff;
1931 texture_state.u = u + tex_offset;
1932 texture_state.v = v;
1933 tex_read(state, &texture_state, &tex_samples[1]);
1935 texture_state.u = u;
1936 texture_state.v = v + tex_offset;
1937 tex_read(state, &texture_state, &tex_samples[2]);
1939 texture_state.u = u + tex_offset;
1940 texture_state.v = v + tex_offset;
1941 tex_read(state, &texture_state, &tex_samples[3]);
1943 d[0] = (256 - du) * (256 - dv);
1944 d[1] = du * (256 - dv);
1945 d[2] = (256 - du) * dv;
1946 d[3] = du * dv;
1948 state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16;
1949 state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16;
1950 state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16;
1951 state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16;
1952 }
1955 static void tex_sample_persp_mipmap(s3d_state_t *state)
1956 {
1957 s3d_texture_state_t texture_state;
1958 int32_t w = 0;
1960 if (state->w)
1961 w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w);
1963 texture_state.level = MAX(MIN(9 - ((state->d >> 27) & 0xf), state->max_d), 0);
1964 texture_state.texture_shift = 18 + (9 - texture_state.level);
1965 texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu;
1966 texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv;
1968 tex_read(state, &texture_state, &state->dest_rgba);
1969 }
1971 static void tex_sample_persp_mipmap_filter(s3d_state_t *state)
1972 {
1973 s3d_texture_state_t texture_state;
1974 int32_t w = 0, u, v;
1975 int tex_offset;
1976 rgba_t tex_samples[4];
1977 int du, dv;
1978 int d[4];
1980 if (state->w)
1981 w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w);
1983 u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu;
1984 v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv;
1986 texture_state.level = MAX(MIN(9 - ((state->d >> 27) & 0xf), state->max_d), 0);
1987 texture_state.texture_shift = 18 + (9 - texture_state.level);
1988 tex_offset = 1 << texture_state.texture_shift;
1990 texture_state.u = u;
1991 texture_state.v = v;
1992 tex_read(state, &texture_state, &tex_samples[0]);
1993 du = (u >> (texture_state.texture_shift - 8)) & 0xff;
1994 dv = (v >> (texture_state.texture_shift - 8)) & 0xff;
1996 texture_state.u = u + tex_offset;
1997 texture_state.v = v;
1998 tex_read(state, &texture_state, &tex_samples[1]);
2000 texture_state.u = u;
2001 texture_state.v = v + tex_offset;
2002 tex_read(state, &texture_state, &tex_samples[2]);
2004 texture_state.u = u + tex_offset;
2005 texture_state.v = v + tex_offset;
2006 tex_read(state, &texture_state, &tex_samples[3]);
2008 d[0] = (256 - du) * (256 - dv);
2009 d[1] = du * (256 - dv);
2010 d[2] = (256 - du) * dv;
2011 d[3] = du * dv;
2013 state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16;
2014 state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16;
2015 state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16;
2016 state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16;
2017 }
2019 static void tex_sample_persp_mipmap_375(s3d_state_t *state)
2020 {
2021 s3d_texture_state_t texture_state;
2022 int32_t w = 0;
2024 if (state->w)
2025 w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w);
2027 texture_state.level = MAX(MIN(9 - ((state->d >> 27) & 0xf), state->max_d), 0);
2028 texture_state.texture_shift = 18 + (9 - texture_state.level);
2029 texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu;
2030 texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv;
2032 tex_read(state, &texture_state, &state->dest_rgba);
2033 }
2035 static void tex_sample_persp_mipmap_filter_375(s3d_state_t *state)
2036 {
2037 s3d_texture_state_t texture_state;
2038 int32_t w = 0, u, v;
2039 int tex_offset;
2040 rgba_t tex_samples[4];
2041 int du, dv;
2042 int d[4];
2044 if (state->w)
2045 w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w);
2047 u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu;
2048 v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv;
2050 texture_state.level = MAX(MIN(9 - ((state->d >> 27) & 0xf), state->max_d), 0);
2051 texture_state.texture_shift = 18 + (9 - texture_state.level);
2052 tex_offset = 1 << texture_state.texture_shift;
2054 texture_state.u = u;
2055 texture_state.v = v;
2056 tex_read(state, &texture_state, &tex_samples[0]);
2057 du = (u >> (texture_state.texture_shift - 8)) & 0xff;
2058 dv = (v >> (texture_state.texture_shift - 8)) & 0xff;
2060 texture_state.u = u + tex_offset;
2061 texture_state.v = v;
2062 tex_read(state, &texture_state, &tex_samples[1]);
2064 texture_state.u = u;
2065 texture_state.v = v + tex_offset;
2066 tex_read(state, &texture_state, &tex_samples[2]);
2068 texture_state.u = u + tex_offset;
2069 texture_state.v = v + tex_offset;
2070 tex_read(state, &texture_state, &tex_samples[3]);
2072 d[0] = (256 - du) * (256 - dv);
2073 d[1] = du * (256 - dv);
2074 d[2] = (256 - du) * dv;
2075 d[3] = du * dv;
2077 state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16;
2078 state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16;
2079 state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16;
2080 state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16;
2081 }
2084 #define CLAMP(x) do \
2085 { \
2086 if ((x) & ~0xff) \
2087 x = ((x) < 0) ? 0 : 0xff; \
2088 } \
2089 while (0)
2091 #define CLAMP_RGBA(r, g, b, a) \
2092 if ((r) & ~0xff) \
2093 r = ((r) < 0) ? 0 : 0xff; \
2094 if ((g) & ~0xff) \
2095 g = ((g) < 0) ? 0 : 0xff; \
2096 if ((b) & ~0xff) \
2097 b = ((b) < 0) ? 0 : 0xff; \
2098 if ((a) & ~0xff) \
2099 a = ((a) < 0) ? 0 : 0xff;
2101 #define CLAMP_RGB(r, g, b) do \
2102 { \
2103 if ((r) < 0) \
2104 r = 0; \
2105 if ((r) > 0xff) \
2106 r = 0xff; \
2107 if ((g) < 0) \
2108 g = 0; \
2109 if ((g) > 0xff) \
2110 g = 0xff; \
2111 if ((b) < 0) \
2112 b = 0; \
2113 if ((b) > 0xff) \
2114 b = 0xff; \
2115 } \
2116 while (0)
2118 static void dest_pixel_gouraud_shaded_triangle(s3d_state_t *state)
2119 {
2120 state->dest_rgba.r = state->r >> 7;
2121 CLAMP(state->dest_rgba.r);
2123 state->dest_rgba.g = state->g >> 7;
2124 CLAMP(state->dest_rgba.g);
2126 state->dest_rgba.b = state->b >> 7;
2127 CLAMP(state->dest_rgba.b);
2129 state->dest_rgba.a = state->a >> 7;
2130 CLAMP(state->dest_rgba.a);
2131 }
2133 static void dest_pixel_unlit_texture_triangle(s3d_state_t *state)
2134 {
2135 tex_sample(state);
2137 if (state->cmd_set & CMD_SET_ABC_SRC)
2138 state->dest_rgba.a = state->a >> 7;
2139 }
2141 static void dest_pixel_lit_texture_decal(s3d_state_t *state)
2142 {
2143 tex_sample(state);
2145 if (state->cmd_set & CMD_SET_ABC_SRC)
2146 state->dest_rgba.a = state->a >> 7;
2147 }
2149 static void dest_pixel_lit_texture_reflection(s3d_state_t *state)
2150 {
2151 tex_sample(state);
2153 state->dest_rgba.r += (state->r >> 7);
2154 state->dest_rgba.g += (state->g >> 7);
2155 state->dest_rgba.b += (state->b >> 7);
2156 if (state->cmd_set & CMD_SET_ABC_SRC)
2157 state->dest_rgba.a += (state->a >> 7);
2159 CLAMP_RGBA(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b, state->dest_rgba.a);
2160 }
2162 static void dest_pixel_lit_texture_modulate(s3d_state_t *state)
2163 {
2164 int r = state->r >> 7, g = state->g >> 7, b = state->b >> 7, a = state->a >> 7;
2166 tex_sample(state);
2168 CLAMP_RGBA(r, g, b, a);
2170 state->dest_rgba.r = ((state->dest_rgba.r) * r) >> 8;
2171 state->dest_rgba.g = ((state->dest_rgba.g) * g) >> 8;
2172 state->dest_rgba.b = ((state->dest_rgba.b) * b) >> 8;
2174 if (state->cmd_set & CMD_SET_ABC_SRC)
2175 state->dest_rgba.a = a;
2176 }
2178 static void tri(virge_t *virge, s3d_state_t *state, int yc, int32_t dx1, int32_t dx2)
2179 {
2180 uint8_t *vram = virge->svga.vram;
2182 int x_dir = virge->s3d.tlr ? 1 : -1;
2184 int use_z = !(virge->s3d.cmd_set & CMD_SET_ZB_MODE);
2186 int y_count = yc;
2188 int bpp = 1;
2190 uint32_t dest_offset, z_offset;
2192 if (virge->s3d.cmd_set & CMD_SET_HC)
2193 {
2194 if (state->y < virge->s3d.clip_t)
2195 return;
2196 if (state->y > virge->s3d.clip_b)
2197 {
2198 int diff_y = state->y - virge->s3d.clip_b;
2200 if (diff_y > y_count)
2201 diff_y = y_count;
2203 state->base_u += (virge->s3d.TdUdY * diff_y);
2204 state->base_v += (virge->s3d.TdVdY * diff_y);
2205 state->base_z += (virge->s3d.TdZdY * diff_y);
2206 state->base_r += (virge->s3d.TdRdY * diff_y);
2207 state->base_g += (virge->s3d.TdGdY * diff_y);
2208 state->base_b += (virge->s3d.TdBdY * diff_y);
2209 state->base_a += (virge->s3d.TdAdY * diff_y);
2210 state->base_d += (virge->s3d.TdDdY * diff_y);
2211 state->base_w += (virge->s3d.TdWdY * diff_y);
2212 state->x1 += (dx1 * diff_y);
2213 state->x2 += (dx2 * diff_y);
2214 state->y -= diff_y;
2215 dest_offset -= virge->s3d.dest_str;
2216 z_offset -= virge->s3d.z_str;
2217 y_count -= diff_y;
2218 }
2219 }
2221 dest_offset = virge->s3d.dest_base + (state->y * virge->s3d.dest_str);
2222 z_offset = virge->s3d.z_base + (state->y * virge->s3d.z_str);
2224 for (; y_count > 0; y_count--)
2225 {
2226 int x = state->x1 >> 20;
2227 int xe = state->x2 >> 20;
2228 uint32_t z = state->base_z;
2229 if (x != xe && (x_dir > 0 && x < xe) || (x_dir < 0 && x > xe))
2230 {
2231 uint32_t dest_addr, z_addr;
2232 int dx = (x_dir > 0) ? 8 - ((state->x1 >> 16) & 0xf) : ((state->x1 >> 16) & 0xf) - 8;
2233 int x_offset = x_dir << bpp;
2235 state->r = state->base_r + ((virge->s3d.TdRdX * dx) >> 4);
2236 state->g = state->base_g + ((virge->s3d.TdGdX * dx) >> 4);
2237 state->b = state->base_b + ((virge->s3d.TdBdX * dx) >> 4);
2238 state->a = state->base_a + ((virge->s3d.TdAdX * dx) >> 4);
2239 state->u = state->base_u + ((virge->s3d.TdUdX * dx) >> 4);
2240 state->v = state->base_v + ((virge->s3d.TdVdX * dx) >> 4);
2241 state->w = state->base_w + ((virge->s3d.TdWdX * dx) >> 4);
2242 state->d = state->base_d + ((virge->s3d.TdDdX * dx) >> 4);
2243 z += ((virge->s3d.TdZdX * dx) >> 4);
2244 // pclog("Draw Y=%i X=%i to XE=%i %i %08x %08x %08x %08x %08x %08x %08x %08x %i %08x\n", state->y, x, xe, dx, state->x1, state->x2, dx1, virge->s3d.TdWdX, state->u, state->v, virge->s3d.TdUdX, virge->s3d.TdUdY, dx, (virge->s3d.TdUdX * dx) >> 4);
2246 if (virge->s3d.cmd_set & CMD_SET_HC)
2247 {
2248 if (x_dir > 0)
2249 {
2250 if (x > virge->s3d.clip_r)
2251 goto tri_skip_line;
2252 if (xe < virge->s3d.clip_l)
2253 goto tri_skip_line;
2254 if (xe > virge->s3d.clip_r)
2255 xe = virge->s3d.clip_r;
2256 if (x < virge->s3d.clip_l)
2257 {
2258 int diff_x = virge->s3d.clip_l - x;
2260 z += (virge->s3d.TdZdX * diff_x);
2261 state->u += (virge->s3d.TdUdX * diff_x);
2262 state->v += (virge->s3d.TdVdX * diff_x);
2263 state->r += (virge->s3d.TdRdX * diff_x);
2264 state->g += (virge->s3d.TdGdX * diff_x);
2265 state->b += (virge->s3d.TdBdX * diff_x);
2266 state->a += (virge->s3d.TdAdX * diff_x);
2267 state->d += (virge->s3d.TdDdX * diff_x);
2268 state->w += (virge->s3d.TdWdX * diff_x);
2270 x = virge->s3d.clip_l;
2271 }
2272 }
2273 else
2274 {
2275 if (x < virge->s3d.clip_l)
2276 goto tri_skip_line;
2277 if (xe > virge->s3d.clip_r)
2278 goto tri_skip_line;
2279 if (xe < virge->s3d.clip_l)
2280 xe = virge->s3d.clip_l;
2281 if (x > virge->s3d.clip_r)
2282 {
2283 int diff_x = x - virge->s3d.clip_r;
2285 z += (virge->s3d.TdZdX * diff_x);
2286 state->u += (virge->s3d.TdUdX * diff_x);
2287 state->v += (virge->s3d.TdVdX * diff_x);
2288 state->r += (virge->s3d.TdRdX * diff_x);
2289 state->g += (virge->s3d.TdGdX * diff_x);
2290 state->b += (virge->s3d.TdBdX * diff_x);
2291 state->a += (virge->s3d.TdAdX * diff_x);
2292 state->d += (virge->s3d.TdDdX * diff_x);
2293 state->w += (virge->s3d.TdWdX * diff_x);
2295 x = virge->s3d.clip_r;
2296 }
2297 }
2298 }
2300 virge->svga.changedvram[(dest_offset & 0x3fffff) >> 12] = changeframecount;
2302 dest_addr = dest_offset + (x << bpp);
2303 z_addr = z_offset + (x << bpp);
2305 for (; x != ((xe + x_dir) & 0xfff); x = (x + x_dir) & 0xfff)
2306 {
2307 int update = 1;
2308 int16_t src_z;
2309 _x = x; _y = state->y;
2311 if (use_z)
2312 {
2313 src_z = Z_READ(z_addr);
2314 Z_CLIP(src_z, z >> 16);
2315 }
2317 if (update)
2318 {
2319 uint32_t dest_col;
2321 dest_pixel(state);
2323 if (virge->s3d.cmd_set & CMD_SET_ABC_ENABLE)
2324 {
2325 uint32_t src_col;
2326 int src_r, src_g, src_b;
2328 switch (bpp)
2329 {
2330 case 0: /*8 bpp*/
2331 /*Not implemented yet*/
2332 break;
2333 case 1: /*16 bpp*/
2334 src_col = *(uint16_t *)&vram[dest_addr & 0x3fffff];
2335 RGB15_TO_24(src_col, src_r, src_g, src_b);
2336 break;
2337 case 2: /*24 bpp*/
2338 src_col = (*(uint32_t *)&vram[dest_addr & 0x3fffff]) & 0xffffff;
2339 RGB24_TO_24(src_col, src_r, src_g, src_b);
2340 break;
2341 }
2343 state->dest_rgba.r = ((state->dest_rgba.r * state->dest_rgba.a) + (src_r * (255 - state->dest_rgba.a))) / 255;
2344 state->dest_rgba.g = ((state->dest_rgba.g * state->dest_rgba.a) + (src_g * (255 - state->dest_rgba.a))) / 255;
2345 state->dest_rgba.b = ((state->dest_rgba.b * state->dest_rgba.a) + (src_b * (255 - state->dest_rgba.a))) / 255;
2346 }
2348 switch (bpp)
2349 {
2350 case 0: /*8 bpp*/
2351 /*Not implemented yet*/
2352 break;
2353 case 1: /*16 bpp*/
2354 dest_col = RGB15(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b);
2355 *(uint16_t *)&vram[dest_addr] = dest_col;
2356 break;
2357 case 2: /*24 bpp*/
2358 dest_col = RGB24(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b);
2359 *(uint32_t *)&vram[dest_addr] = dest_col;
2360 break;
2361 }
2363 if (use_z)
2364 Z_WRITE(z_addr, src_z);
2365 }
2367 z += virge->s3d.TdZdX;
2368 state->u += virge->s3d.TdUdX;
2369 state->v += virge->s3d.TdVdX;
2370 state->r += virge->s3d.TdRdX;
2371 state->g += virge->s3d.TdGdX;
2372 state->b += virge->s3d.TdBdX;
2373 state->a += virge->s3d.TdAdX;
2374 state->d += virge->s3d.TdDdX;
2375 state->w += virge->s3d.TdWdX;
2376 dest_addr += x_offset;
2377 z_addr += x_offset;
2378 virge->pixel_count++;
2379 }
2380 }
2381 tri_skip_line:
2382 state->x1 += dx1;
2383 state->x2 += dx2;
2384 state->base_u += virge->s3d.TdUdY;
2385 state->base_v += virge->s3d.TdVdY;
2386 state->base_z += virge->s3d.TdZdY;
2387 state->base_r += virge->s3d.TdRdY;
2388 state->base_g += virge->s3d.TdGdY;
2389 state->base_b += virge->s3d.TdBdY;
2390 state->base_a += virge->s3d.TdAdY;
2391 state->base_d += virge->s3d.TdDdY;
2392 state->base_w += virge->s3d.TdWdY;
2393 state->y--;
2394 dest_offset -= virge->s3d.dest_str;
2395 z_offset -= virge->s3d.z_str;
2396 }
2397 }
2399 static int tex_size[8] =
2400 {
2401 4*2,
2402 2*2,
2403 2*2,
2404 1*2,
2405 2/1,
2406 2/1,
2407 1*2,
2408 1*2
2409 };
2411 static void s3_virge_triangle(virge_t *virge)
2412 {
2413 s3d_state_t state;
2415 uint32_t tex_base;
2416 int c;
2418 uint64_t start_time = timer_read();
2419 uint64_t end_time;
2421 state.tbu = virge->s3d.tbu << 11;
2422 state.tbv = virge->s3d.tbv << 11;
2424 state.max_d = (virge->s3d.cmd_set >> 8) & 15;
2426 state.tex_bdr_clr = virge->s3d.tex_bdr_clr;
2428 state.cmd_set = virge->s3d.cmd_set;
2430 state.base_u = virge->s3d.tus;
2431 state.base_v = virge->s3d.tvs;
2432 state.base_z = virge->s3d.tzs;
2433 state.base_r = (int32_t)virge->s3d.trs;
2434 state.base_g = (int32_t)virge->s3d.tgs;
2435 state.base_b = (int32_t)virge->s3d.tbs;
2436 state.base_a = (int32_t)virge->s3d.tas;
2437 state.base_d = virge->s3d.tds;
2438 state.base_w = virge->s3d.tws;
2440 tex_base = virge->s3d.tex_base;
2441 for (c = 9; c >= 0; c--)
2442 {
2443 state.texture[c] = (uint16_t *)&virge->svga.vram[tex_base];
2444 if (c <= state.max_d)
2445 tex_base += ((1 << (c*2)) * tex_size[(virge->s3d.cmd_set >> 5) & 7]) / 2;
2446 }
2448 switch ((virge->s3d.cmd_set >> 27) & 0xf)
2449 {
2450 case 0:
2451 dest_pixel = dest_pixel_gouraud_shaded_triangle;
2452 // pclog("dest_pixel_gouraud_shaded_triangle\n");
2453 break;
2454 case 1:
2455 case 5:
2456 switch ((virge->s3d.cmd_set >> 15) & 0x3)
2457 {
2458 case 0:
2459 dest_pixel = dest_pixel_lit_texture_reflection;
2460 // pclog("dest_pixel_lit_texture_reflection\n");
2461 break;
2462 case 1:
2463 dest_pixel = dest_pixel_lit_texture_modulate;
2464 // pclog("dest_pixel_lit_texture_modulate\n");
2465 break;
2466 case 2:
2467 dest_pixel = dest_pixel_lit_texture_decal;
2468 // pclog("dest_pixel_lit_texture_decal\n");
2469 break;
2470 default:
2471 pclog("bad triangle type %x\n", (virge->s3d.cmd_set >> 27) & 0xf);
2472 return;
2473 }
2474 break;
2475 case 2:
2476 case 6:
2477 dest_pixel = dest_pixel_unlit_texture_triangle;
2478 // pclog("dest_pixel_unlit_texture_triangle\n");
2479 break;
2480 default:
2481 pclog("bad triangle type %x\n", (virge->s3d.cmd_set >> 27) & 0xf);
2482 return;
2483 }
2485 switch (((virge->s3d.cmd_set >> 12) & 7) | ((virge->s3d.cmd_set & (1 << 29)) ? 8 : 0))
2486 {
2487 case 0: case 1:
2488 tex_sample = tex_sample_mipmap;
2489 // pclog("use tex_sample_mipmap\n");
2490 break;
2491 case 2: case 3:
2492 tex_sample = virge->bilinear_enabled ? tex_sample_mipmap_filter : tex_sample_mipmap;
2493 // pclog("use tex_sample_mipmap_filter\n");
2494 break;
2495 case 4: case 5:
2496 tex_sample = tex_sample_normal;
2497 // pclog("use tex_sample_normal\n");
2498 break;
2499 case 6: case 7:
2500 tex_sample = virge->bilinear_enabled ? tex_sample_normal_filter : tex_sample_normal;
2501 // pclog("use tex_sample_normal_filter\n");
2502 break;
2503 case (0 | 8): case (1 | 8):
2504 if (virge->is_375)
2505 tex_sample = tex_sample_persp_mipmap_375;
2506 else
2507 tex_sample = tex_sample_persp_mipmap;
2508 // pclog("use tex_sample_persp_mipmap\n");
2509 break;
2510 case (2 | 8): case (3 | 8):
2511 if (virge->is_375)
2512 tex_sample = virge->bilinear_enabled ? tex_sample_persp_mipmap_filter_375 : tex_sample_persp_mipmap_375;
2513 else
2514 tex_sample = virge->bilinear_enabled ? tex_sample_persp_mipmap_filter : tex_sample_persp_mipmap;
2515 // pclog("use tex_sample_persp_mipmap_filter\n");
2516 break;
2517 case (4 | 8): case (5 | 8):
2518 if (virge->is_375)
2519 tex_sample = tex_sample_persp_normal_375;
2520 else
2521 tex_sample = tex_sample_persp_normal;
2522 // pclog("use tex_sample_persp_normal\n");
2523 break;
2524 case (6 | 8): case (7 | 8):
2525 if (virge->is_375)
2526 tex_sample = virge->bilinear_enabled ? tex_sample_persp_normal_filter_375 : tex_sample_persp_normal_375;
2527 else
2528 tex_sample = virge->bilinear_enabled ? tex_sample_persp_normal_filter : tex_sample_persp_normal;
2529 // pclog("use tex_sample_persp_normal_filter\n");
2530 break;
2531 }
2533 switch ((virge->s3d.cmd_set >> 5) & 7)
2534 {
2535 case 0:
2536 tex_read = (virge->s3d.cmd_set & CMD_SET_TWE) ? tex_ARGB8888 : tex_ARGB8888_nowrap;
2537 break;
2538 case 1:
2539 tex_read = (virge->s3d.cmd_set & CMD_SET_TWE) ? tex_ARGB4444 : tex_ARGB4444_nowrap;
2540 // pclog("tex_ARGB4444\n");
2541 break;
2542 case 2:
2543 tex_read = (virge->s3d.cmd_set & CMD_SET_TWE) ? tex_ARGB1555 : tex_ARGB1555_nowrap;
2544 // pclog("tex_ARGB1555 %i\n", (virge->s3d.cmd_set >> 5) & 7);
2545 break;
2546 default:
2547 pclog("bad texture type %i\n", (virge->s3d.cmd_set >> 5) & 7);
2548 tex_read = (virge->s3d.cmd_set & CMD_SET_TWE) ? tex_ARGB1555 : tex_ARGB1555_nowrap;
2549 break;
2550 }
2552 // pclog("Triangle %i %i,%i to %i,%i %08x\n", y, x1 >> 20, y, virge->s3d.txend01 >> 20, y - (virge->s3d.ty01 + virge->s3d.ty12), state.cmd_set);
2554 state.y = virge->s3d.tys;
2555 state.x1 = virge->s3d.txs;
2556 state.x2 = virge->s3d.txend01;
2557 tri(virge, &state, virge->s3d.ty01, virge->s3d.TdXdY02, virge->s3d.TdXdY01);
2558 state.x2 = virge->s3d.txend12;
2559 tri(virge, &state, virge->s3d.ty12, virge->s3d.TdXdY02, virge->s3d.TdXdY12);
2561 virge->tri_count++;
2563 end_time = timer_read();
2565 virge_time += end_time - start_time;
2566 }
2569 static void s3_virge_hwcursor_draw(svga_t *svga, int displine)
2570 {
2571 int x;
2572 uint16_t dat[2];
2573 int xx;
2574 int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff;
2576 // pclog("HWcursor %i %i\n", svga->hwcursor_latch.x, svga->hwcursor_latch.y);
2577 for (x = 0; x < 64; x += 16)
2578 {
2579 dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 8) | svga->vram[svga->hwcursor_latch.addr + 1];
2580 dat[1] = (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3];
2581 for (xx = 0; xx < 16; xx++)
2582 {
2583 if (offset >= svga->hwcursor_latch.x)
2584 {
2585 if (!(dat[0] & 0x8000))
2586 ((uint32_t *)buffer32->line[displine])[offset + 32] = (dat[1] & 0x8000) ? 0xffffff : 0;
2587 else if (dat[1] & 0x8000)
2588 ((uint32_t *)buffer32->line[displine])[offset + 32] ^= 0xffffff;
2589 // pclog("Plot %i, %i (%i %i) %04X %04X\n", offset, displine, x+xx, svga->hwcursor_on, dat[0], dat[1]);
2590 }
2592 offset++;
2593 dat[0] <<= 1;
2594 dat[1] <<= 1;
2595 }
2596 svga->hwcursor_latch.addr += 4;
2597 }
2598 }
2600 #define DECODE_YCbCr() \
2601 do \
2602 { \
2603 int c; \
2604 \
2605 for (c = 0; c < 2; c++) \
2606 { \
2607 uint8_t y1, y2; \
2608 int8_t Cr, Cb; \
2609 int dR, dG, dB; \
2610 \
2611 y1 = src[0]; \
2612 Cr = src[1] - 0x80; \
2613 y2 = src[2]; \
2614 Cb = src[3] - 0x80; \
2615 src += 4; \
2616 \
2617 dR = (359*Cr) >> 8; \
2618 dG = (88*Cb + 183*Cr) >> 8; \
2619 dB = (453*Cb) >> 8; \
2620 \
2621 r[x_write] = y1 + dR; \
2622 CLAMP(r[x_write]); \
2623 g[x_write] = y1 - dG; \
2624 CLAMP(g[x_write]); \
2625 b[x_write] = y1 + dB; \
2626 CLAMP(b[x_write]); \
2627 \
2628 r[x_write+1] = y2 + dR; \
2629 CLAMP(r[x_write+1]); \
2630 g[x_write+1] = y2 - dG; \
2631 CLAMP(g[x_write+1]); \
2632 b[x_write+1] = y2 + dB; \
2633 CLAMP(b[x_write+1]); \
2634 \
2635 x_write = (x_write + 2) & 7; \
2636 } \
2637 } while (0)
2639 /*Both YUV formats are untested*/
2640 #define DECODE_YUV211() \
2641 do \
2642 { \
2643 uint8_t y1, y2, y3, y4; \
2644 int8_t U, V; \
2645 int dR, dG, dB; \
2646 \
2647 U = src[0] - 0x80; \
2648 y1 = (298 * (src[1] - 16)) >> 8; \
2649 y2 = (298 * (src[2] - 16)) >> 8; \
2650 V = src[3] - 0x80; \
2651 y3 = (298 * (src[4] - 16)) >> 8; \
2652 y4 = (298 * (src[5] - 16)) >> 8; \
2653 src += 6; \
2654 \
2655 dR = (309*V) >> 8; \
2656 dG = (100*U + 208*V) >> 8; \
2657 dB = (516*U) >> 8; \
2658 \
2659 r[x_write] = y1 + dR; \
2660 CLAMP(r[x_write]); \
2661 g[x_write] = y1 - dG; \
2662 CLAMP(g[x_write]); \
2663 b[x_write] = y1 + dB; \
2664 CLAMP(b[x_write]); \
2665 \
2666 r[x_write+1] = y2 + dR; \
2667 CLAMP(r[x_write+1]); \
2668 g[x_write+1] = y2 - dG; \
2669 CLAMP(g[x_write+1]); \
2670 b[x_write+1] = y2 + dB; \
2671 CLAMP(b[x_write+1]); \
2672 \
2673 r[x_write+2] = y2 + dR; \
2674 CLAMP(r[x_write+2]); \
2675 g[x_write+2] = y2 - dG; \
2676 CLAMP(g[x_write+2]); \
2677 b[x_write+2] = y2 + dB; \
2678 CLAMP(b[x_write+2]); \
2679 \
2680 r[x_write+3] = y2 + dR; \
2681 CLAMP(r[x_write+3]); \
2682 g[x_write+3] = y2 - dG; \
2683 CLAMP(g[x_write+3]); \
2684 b[x_write+3] = y2 + dB; \
2685 CLAMP(b[x_write+3]); \
2686 \
2687 x_write = (x_write + 4) & 7; \
2688 } while (0)
2690 #define DECODE_YUV422() \
2691 do \
2692 { \
2693 int c; \
2694 \
2695 for (c = 0; c < 2; c++) \
2696 { \
2697 uint8_t y1, y2; \
2698 int8_t U, V; \
2699 int dR, dG, dB; \
2700 \
2701 U = src[0] - 0x80; \
2702 y1 = (298 * (src[1] - 16)) >> 8; \
2703 V = src[2] - 0x80; \
2704 y2 = (298 * (src[3] - 16)) >> 8; \
2705 src += 4; \
2706 \
2707 dR = (309*V) >> 8; \
2708 dG = (100*U + 208*V) >> 8; \
2709 dB = (516*U) >> 8; \
2710 \
2711 r[x_write] = y1 + dR; \
2712 CLAMP(r[x_write]); \
2713 g[x_write] = y1 - dG; \
2714 CLAMP(g[x_write]); \
2715 b[x_write] = y1 + dB; \
2716 CLAMP(b[x_write]); \
2717 \
2718 r[x_write+1] = y2 + dR; \
2719 CLAMP(r[x_write+1]); \
2720 g[x_write+1] = y2 - dG; \
2721 CLAMP(g[x_write+1]); \
2722 b[x_write+1] = y2 + dB; \
2723 CLAMP(b[x_write+1]); \
2724 \
2725 x_write = (x_write + 2) & 7; \
2726 } \
2727 } while (0)
2729 #define DECODE_RGB555() \
2730 do \
2731 { \
2732 int c; \
2733 \
2734 for (c = 0; c < 4; c++) \
2735 { \
2736 uint16_t dat; \
2737 \
2738 dat = *(uint16_t *)src; \
2739 src += 2; \
2740 \
2741 r[x_write + c] = ((dat & 0x001f) << 3) | ((dat & 0x001f) >> 2); \
2742 g[x_write + c] = ((dat & 0x03e0) >> 2) | ((dat & 0x03e0) >> 7); \
2743 b[x_write + c] = ((dat & 0x7c00) >> 7) | ((dat & 0x7c00) >> 12); \
2744 } \
2745 x_write = (x_write + 4) & 7; \
2746 } while (0)
2748 #define DECODE_RGB565() \
2749 do \
2750 { \
2751 int c; \
2752 \
2753 for (c = 0; c < 4; c++) \
2754 { \
2755 uint16_t dat; \
2756 \
2757 dat = *(uint16_t *)src; \
2758 src += 2; \
2759 \
2760 r[x_write + c] = ((dat & 0x001f) << 3) | ((dat & 0x001f) >> 2); \
2761 g[x_write + c] = ((dat & 0x07e0) >> 3) | ((dat & 0x07e0) >> 9); \
2762 b[x_write + c] = ((dat & 0xf800) >> 8) | ((dat & 0xf800) >> 13); \
2763 } \
2764 x_write = (x_write + 4) & 7; \
2765 } while (0)
2767 #define DECODE_RGB888() \
2768 do \
2769 { \
2770 int c; \
2771 \
2772 for (c = 0; c < 4; c++) \
2773 { \
2774 r[x_write + c] = src[0]; \
2775 g[x_write + c] = src[1]; \
2776 b[x_write + c] = src[2]; \
2777 src += 3; \
2778 } \
2779 x_write = (x_write + 4) & 7; \
2780 } while (0)
2782 #define DECODE_XRGB8888() \
2783 do \
2784 { \
2785 int c; \
2786 \
2787 for (c = 0; c < 4; c++) \
2788 { \
2789 r[x_write + c] = src[0]; \
2790 g[x_write + c] = src[1]; \
2791 b[x_write + c] = src[2]; \
2792 src += 4; \
2793 } \
2794 x_write = (x_write + 4) & 7; \
2795 } while (0)
2797 #define OVERLAY_SAMPLE() \
2798 do \
2799 { \
2800 switch (virge->streams.sdif) \
2801 { \
2802 case 1: \
2803 DECODE_YCbCr(); \
2804 break; \
2805 case 2: \
2806 DECODE_YUV422(); \
2807 break; \
2808 case 3: \
2809 DECODE_RGB555(); \
2810 break; \
2811 case 4: \
2812 DECODE_YUV211(); \
2813 break; \
2814 case 5: \
2815 DECODE_RGB565(); \
2816 break; \
2817 case 6: \
2818 DECODE_RGB888(); \
2819 break; \
2820 case 7: \
2821 default: \
2822 DECODE_XRGB8888(); \
2823 break; \
2824 } \
2825 } while (0)
2827 static void s3_virge_overlay_draw(svga_t *svga, int displine)
2828 {
2829 virge_t *virge = (virge_t *)svga->p;
2830 int offset = (virge->streams.sec_x - virge->streams.pri_x) + 1;
2831 int h_acc = virge->streams.dda_horiz_accumulator;
2832 int r[8], g[8], b[8];
2833 int r_samp[8] = {0, 0, 0, 0, 0, 0, 0, 0};
2834 int g_samp[8] = {0, 0, 0, 0, 0, 0, 0, 0};
2835 int b_samp[8] = {0, 0, 0, 0, 0, 0, 0, 0};
2836 int x_size, x_read = 4, x_write = 4;
2837 int x;
2838 uint32_t *p;
2839 uint8_t *src = &svga->vram[svga->overlay_latch.addr];
2841 p = &((uint32_t *)buffer32->line[displine])[offset + 32];
2843 if ((offset + virge->streams.sec_w) > virge->streams.pri_w)
2844 x_size = (virge->streams.pri_w - virge->streams.sec_x) + 1;
2845 else
2846 x_size = virge->streams.sec_w + 1;
2848 OVERLAY_SAMPLE();
2850 for (x = 0; x < x_size; x++)
2851 {
2852 *p++ = r[x_read] | (g[x_read] << 8) | (b[x_read] << 16);
2854 h_acc += virge->streams.k1_horiz_scale;
2855 if (h_acc >= 0)
2856 {
2857 if ((x_read ^ (x_read + 1)) & ~3)
2858 OVERLAY_SAMPLE();
2859 x_read = (x_read + 1) & 7;
2861 h_acc += (virge->streams.k2_horiz_scale - virge->streams.k1_horiz_scale);
2862 }
2863 }
2865 svga->overlay_latch.v_acc += virge->streams.k1_vert_scale;
2866 if (svga->overlay_latch.v_acc >= 0)
2867 {
2868 svga->overlay_latch.v_acc += (virge->streams.k2_vert_scale - virge->streams.k1_vert_scale);
2869 svga->overlay_latch.addr += virge->streams.sec_stride;
2870 }
2871 }
2873 static uint8_t s3_virge_pci_read(int func, int addr, void *p)
2874 {
2875 virge_t *virge = (virge_t *)p;
2876 svga_t *svga = &virge->svga;
2877 uint8_t ret = 0;
2878 // pclog("S3 PCI read %08X ", addr);
2879 switch (addr)
2880 {
2881 case 0x00: ret = 0x33; break; /*'S3'*/
2882 case 0x01: ret = 0x53; break;
2884 case 0x02: ret = virge->virge_id_low; break;
2885 case 0x03: ret = virge->virge_id_high; break;
2887 case 0x04: ret = virge->pci_regs[0x04] & 0x27; break;
2889 case 0x07: ret = virge->pci_regs[0x07] & 0x36; break;
2891 case 0x08: ret = 0; break; /*Revision ID*/
2892 case 0x09: ret = 0; break; /*Programming interface*/
2894 case 0x0a: ret = 0x00; break; /*Supports VGA interface*/
2895 case 0x0b: ret = 0x03; /*output = 3; */break;
2897 case 0x0d: ret = virge->pci_regs[0x0d] & 0xf8; break;
2899 case 0x10: ret = 0x00; break;/*Linear frame buffer address*/
2900 case 0x11: ret = 0x00; break;
2901 case 0x12: ret = 0x00; break;
2902 case 0x13: ret = svga->crtc[0x59] & 0xfc; break;
2904 case 0x30: ret = virge->pci_regs[0x30] & 0x01; break; /*BIOS ROM address*/
2905 case 0x31: ret = 0x00; break;
2906 case 0x32: ret = virge->pci_regs[0x32]; break;
2907 case 0x33: ret = virge->pci_regs[0x33]; break;
2909 case 0x3c: ret = virge->pci_regs[0x3c]; break;
2911 case 0x3d: ret = 0x01; break; /*INTA*/
2913 case 0x3e: ret = 0x04; break;
2914 case 0x3f: ret = 0xff; break;
2916 }
2917 // pclog("%02X\n", ret);
2918 return ret;
2919 }
2921 static void s3_virge_pci_write(int func, int addr, uint8_t val, void *p)
2922 {
2923 virge_t *virge = (virge_t *)p;
2924 svga_t *svga = &virge->svga;
2925 // pclog("S3 PCI write %08X %02X %04X:%08X\n", addr, val, CS, pc);
2926 switch (addr)
2927 {
2928 case 0x00: case 0x01: case 0x02: case 0x03:
2929 case 0x08: case 0x09: case 0x0a: case 0x0b:
2930 case 0x3d: case 0x3e: case 0x3f:
2931 return;
2933 case PCI_REG_COMMAND:
2934 if (val & PCI_COMMAND_IO)
2935 {
2936 io_removehandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge);
2937 io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge);
2938 }
2939 else
2940 io_removehandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge);
2941 virge->pci_regs[PCI_REG_COMMAND] = val & 0x27;
2942 return;
2943 case 0x07:
2944 virge->pci_regs[0x07] = val & 0x3e;
2945 return;
2946 case 0x0d:
2947 virge->pci_regs[0x0d] = val & 0xf8;
2948 return;
2950 case 0x13:
2951 svga->crtc[0x59] = val & 0xfc;
2952 s3_virge_updatemapping(virge);
2953 return;
2955 case 0x30: case 0x32: case 0x33:
2956 virge->pci_regs[addr] = val;
2957 if (virge->pci_regs[0x30] & 0x01)
2958 {
2959 uint32_t addr = (virge->pci_regs[0x32] << 16) | (virge->pci_regs[0x33] << 24);
2960 // pclog("Virge bios_rom enabled at %08x\n", addr);
2961 mem_mapping_set_addr(&virge->bios_rom.mapping, addr, 0x8000);
2962 mem_mapping_enable(&virge->bios_rom.mapping);
2963 }
2964 else
2965 {
2966 // pclog("Virge bios_rom disabled\n");
2967 mem_mapping_disable(&virge->bios_rom.mapping);
2968 }
2969 return;
2970 case 0x3c:
2971 virge->pci_regs[0x3c] = val;
2972 return;
2973 }
2974 }
2976 static void *s3_virge_init()
2977 {
2978 virge_t *virge = malloc(sizeof(virge_t));
2979 memset(virge, 0, sizeof(virge_t));
2981 virge->bilinear_enabled = device_get_config_int("bilinear");
2982 virge->memory_size = device_get_config_int("memory");
2983 pclog("bilinear_enabled=%i memory_size=%i\n", virge->bilinear_enabled, virge->memory_size);
2985 svga_init(&virge->svga, virge, virge->memory_size << 20,
2986 s3_virge_recalctimings,
2987 s3_virge_in, s3_virge_out,
2988 s3_virge_hwcursor_draw,
2989 s3_virge_overlay_draw);
2991 rom_init(&virge->bios_rom, "roms/s3virge.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
2992 if (PCI)
2993 mem_mapping_disable(&virge->bios_rom.mapping);
2995 mem_mapping_add(&virge->mmio_mapping, 0, 0, s3_virge_mmio_read,
2996 s3_virge_mmio_read_w,
2997 s3_virge_mmio_read_l,
2998 s3_virge_mmio_write,
2999 s3_virge_mmio_write_w,
3000 s3_virge_mmio_write_l,
3001 NULL,
3002 0,
3003 virge);
3004 mem_mapping_add(&virge->new_mmio_mapping, 0, 0, s3_virge_mmio_read,
3005 s3_virge_mmio_read_w,
3006 s3_virge_mmio_read_l,
3007 s3_virge_mmio_write,
3008 s3_virge_mmio_write_w,
3009 s3_virge_mmio_write_l,
3010 NULL,
3011 0,
3012 virge);
3013 mem_mapping_add(&virge->linear_mapping, 0, 0, svga_read_linear,
3014 svga_readw_linear,
3015 svga_readl_linear,
3016 svga_write_linear,
3017 svga_writew_linear,
3018 svga_writel_linear,
3019 NULL,
3020 0,
3021 &virge->svga);
3023 io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge);
3025 virge->pci_regs[4] = 3;
3026 virge->pci_regs[5] = 0;
3027 virge->pci_regs[6] = 0;
3028 virge->pci_regs[7] = 2;
3029 virge->pci_regs[0x32] = 0x0c;
3030 virge->pci_regs[0x3d] = 1;
3031 virge->pci_regs[0x3e] = 4;
3032 virge->pci_regs[0x3f] = 0xff;
3034 virge->virge_id_high = 0x56;
3035 virge->virge_id_low = 0x31;
3036 virge->virge_rev = 0;
3037 virge->virge_id = 0xe1;
3039 switch (virge->memory_size)
3040 {
3041 case 2:
3042 virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (4 << 5);
3043 break;
3044 case 4:
3045 default:
3046 virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (0 << 5);
3047 break;
3048 }
3050 virge->svga.crtc[0x37] = 1;// | (7 << 5);
3051 virge->svga.crtc[0x53] = 1 << 3;
3052 virge->svga.crtc[0x59] = 0x70;
3054 virge->is_375 = 0;
3056 pci_add(s3_virge_pci_read, s3_virge_pci_write, virge);
3058 return virge;
3059 }
3061 static void *s3_virge_375_init()
3062 {
3063 virge_t *virge = malloc(sizeof(virge_t));
3064 memset(virge, 0, sizeof(virge_t));
3066 virge->bilinear_enabled = device_get_config_int("bilinear");
3067 virge->memory_size = device_get_config_int("memory");
3068 pclog("bilinear_enabled=%i memory_size=%i\n", virge->bilinear_enabled, virge->memory_size);
3070 svga_init(&virge->svga, virge, virge->memory_size << 20,
3071 s3_virge_recalctimings,
3072 s3_virge_in, s3_virge_out,
3073 s3_virge_hwcursor_draw,
3074 s3_virge_overlay_draw);
3076 rom_init(&virge->bios_rom, "roms/86c375_1.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
3077 if (PCI)
3078 mem_mapping_disable(&virge->bios_rom.mapping);
3080 mem_mapping_add(&virge->mmio_mapping, 0, 0, s3_virge_mmio_read,
3081 s3_virge_mmio_read_w,
3082 s3_virge_mmio_read_l,
3083 s3_virge_mmio_write,
3084 s3_virge_mmio_write_w,
3085 s3_virge_mmio_write_l,
3086 NULL,
3087 0,
3088 virge);
3089 mem_mapping_add(&virge->new_mmio_mapping, 0, 0, s3_virge_mmio_read,
3090 s3_virge_mmio_read_w,
3091 s3_virge_mmio_read_l,
3092 s3_virge_mmio_write,
3093 s3_virge_mmio_write_w,
3094 s3_virge_mmio_write_l,
3095 NULL,
3096 0,
3097 virge);
3098 mem_mapping_add(&virge->linear_mapping, 0, 0, svga_read_linear,
3099 svga_readw_linear,
3100 svga_readl_linear,
3101 svga_write_linear,
3102 svga_writew_linear,
3103 svga_writel_linear,
3104 NULL,
3105 0,
3106 &virge->svga);
3108 io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge);
3110 virge->pci_regs[4] = 3;
3111 virge->pci_regs[5] = 0;
3112 virge->pci_regs[6] = 0;
3113 virge->pci_regs[7] = 2;
3114 virge->pci_regs[0x32] = 0x0c;
3115 virge->pci_regs[0x3d] = 1;
3116 virge->pci_regs[0x3e] = 4;
3117 virge->pci_regs[0x3f] = 0xff;
3119 virge->virge_id_high = 0x8a;
3120 virge->virge_id_low = 0x01;
3121 virge->virge_rev = 0;
3122 virge->virge_id = 0xe1;
3124 switch (virge->memory_size)
3125 {
3126 case 2:
3127 virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (4 << 5);
3128 break;
3129 case 4:
3130 default:
3131 virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (0 << 5);
3132 break;
3133 }
3134 // virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4);
3135 virge->svga.crtc[0x37] = 1;// | (7 << 5);
3136 virge->svga.crtc[0x53] = 1 << 3;
3137 virge->svga.crtc[0x59] = 0x70;
3139 virge->svga.crtc[0x6c] = 0x01;
3141 virge->is_375 = 1;
3143 pci_add(s3_virge_pci_read, s3_virge_pci_write, virge);
3145 return virge;
3146 }
3148 static void s3_virge_close(void *p)
3149 {
3150 virge_t *virge = (virge_t *)p;
3151 FILE *f = fopen("vram.dmp", "wb");
3152 fwrite(virge->svga.vram, 4 << 20, 1, f);
3153 fclose(f);
3155 svga_close(&virge->svga);
3157 free(virge);
3158 }
3160 static int s3_virge_available()
3161 {
3162 return rom_present("roms/s3virge.bin");
3163 }
3165 static int s3_virge_375_available()
3166 {
3167 return rom_present("roms/86c375_1.bin");
3168 }
3170 static void s3_virge_speed_changed(void *p)
3171 {
3172 virge_t *virge = (virge_t *)p;
3174 svga_recalctimings(&virge->svga);
3175 }
3177 static void s3_virge_force_redraw(void *p)
3178 {
3179 virge_t *virge = (virge_t *)p;
3181 virge->svga.fullchange = changeframecount;
3182 }
3184 static int s3_virge_add_status_info(char *s, int max_len, void *p)
3185 {
3186 virge_t *virge = (virge_t *)p;
3187 int cur_len;
3188 char temps[256];
3190 uint64_t new_time = timer_read();
3191 uint64_t status_diff = new_time - status_time;
3192 status_time = new_time;
3194 if (!status_diff)
3195 status_diff = 1;
3197 cur_len = svga_add_status_info(s, cur_len, &virge->svga);
3198 sprintf(temps, "%f Mpixels/sec\n%f ktris/sec\n%f%% CPU\n%f%% CPU (real)\n%d writes", (double)virge->pixel_count/1000000.0, (double)virge->tri_count/1000.0, ((double)virge_time * 100.0) / timer_freq, ((double)virge_time * 100.0) / status_diff, reg_writes);
3199 strncat(s, temps, cur_len);
3200 cur_len -= strlen(temps);
3201 virge->pixel_count = virge->tri_count = 0;
3202 virge_time = 0;
3203 reg_writes = 0;
3205 return max_len - cur_len;
3206 }
3208 static device_config_t s3_virge_config[] =
3209 {
3210 {
3211 .name = "bilinear",
3212 .description = "Bilinear filtering",
3213 .type = CONFIG_BINARY,
3214 .default_int = 1
3215 },
3216 {
3217 .name = "memory",
3218 .description = "Memory size",
3219 .type = CONFIG_SELECTION,
3220 .selection =
3221 {
3222 {
3223 .description = "2 MB",
3224 .value = 2
3225 },
3226 {
3227 .description = "4 MB",
3228 .value = 4
3229 },
3230 {
3231 .description = ""
3232 }
3233 },
3234 .default_int = 4
3235 },
3236 {
3237 .type = -1
3238 }
3239 };
3241 device_t s3_virge_device =
3242 {
3243 "Diamond Stealth 3D 2000 (S3 ViRGE)",
3244 DEVICE_NOT_WORKING,
3245 s3_virge_init,
3246 s3_virge_close,
3247 s3_virge_available,
3248 s3_virge_speed_changed,
3249 s3_virge_force_redraw,
3250 s3_virge_add_status_info,
3251 s3_virge_config
3252 };
3254 device_t s3_virge_375_device =
3255 {
3256 "S3 ViRGE/DX",
3257 DEVICE_NOT_WORKING,
3258 s3_virge_375_init,
3259 s3_virge_close,
3260 s3_virge_375_available,
3261 s3_virge_speed_changed,
3262 s3_virge_force_redraw,
3263 s3_virge_add_status_info,
3264 s3_virge_config
3265 };
