summaryrefslogtreecommitdiff
path: root/sys/src/cmd/aux/vga/virge.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/aux/vga/virge.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/aux/vga/virge.c')
-rwxr-xr-xsys/src/cmd/aux/vga/virge.c758
1 files changed, 758 insertions, 0 deletions
diff --git a/sys/src/cmd/aux/vga/virge.c b/sys/src/cmd/aux/vga/virge.c
new file mode 100755
index 000000000..c22bce8c1
--- /dev/null
+++ b/sys/src/cmd/aux/vga/virge.c
@@ -0,0 +1,758 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+#include "pci.h"
+#include "vga.h"
+
+/*
+ * S3 Trio/ViRGE/Savage4
+ * Requires work.
+ */
+
+/* on some cards, savage4mem[1] == 8, but i don't know how to tell. -rsc */
+static uchar savage4mem[] = { 2, 4, 8, 12, 16, 32, 0, 32};
+static void
+snarf(Vga* vga, Ctlr* ctlr)
+{
+ int i, id;
+ char *p;
+
+ /*
+ * The Trio/ViRGE variants have some extra sequencer registers
+ * which need to be unlocked for access.
+ */
+ vgaxo(Seqx, 0x08, 0x06);
+ s3generic.snarf(vga, ctlr);
+
+ for(i = 0x08; i < 0x4F; i++)
+ vga->sequencer[i] = vgaxi(Seqx, i);
+ vga->crt[0x2D] = vgaxi(Crtx, 0x2D);
+ vga->crt[0x2E] = vgaxi(Crtx, 0x2E);
+ vga->crt[0x2F] = vgaxi(Crtx, 0x2F);
+ for(i = 0x70; i < 0x99; i++)
+ vga->crt[i] = vgaxi(Crtx, i);
+
+ id = (vga->crt[0x2D]<<8)|vga->crt[0x2E];
+ switch(id){
+
+ default:
+ trace("Unknown ViRGE/Trio64+ - 0x%4.4uX\n",
+ (vga->crt[0x2D]<<8)|vga->crt[0x2E]);
+ /*FALLTHROUGH*/
+
+ case 0x8810: /* Microsoft Virtual PC 2004 */
+ case 0x8811: /* Trio64+ */
+ vga->r[1] = 3;
+ vga->m[1] = 127;
+ vga->n[1] = 31;
+ vga->f[1] = 135000000;
+ trace("Trio64+\n");
+ break;
+
+ case 0x8812: /* Aurora64V+ */
+ vga->r[1] = 3;
+ vga->m[1] = 127;
+ vga->n[1] = 63;
+ vga->f[1] = 135000000;
+ trace("Aurora64V+\n");
+ break;
+
+ case 0x8901: /* Trio64V2 */
+ vga->r[1] = 4;
+ vga->m[1] = 127;
+ vga->n[1] = 31;
+ vga->f[1] = 170000000;
+ trace("Trio64V2\n");
+ break;
+
+ case 0x5631: /* ViRGE */
+ vga->r[1] = 3;
+ vga->m[1] = 127;
+ vga->n[1] = 31;
+ vga->f[1] = 135000000;
+ vga->apz = 64*1024*1024;
+ trace("ViRGE\n");
+ break;
+
+ case 0x8A01: /* ViRGE/[DG]X */
+ vga->r[1] = 4;
+ vga->m[1] = 127;
+ vga->n[1] = 31;
+ vga->f[1] = 170000000;
+ trace("ViRGE/[DG]X\n");
+ break;
+
+ case 0x8A10: /* ViRGE/GX2 */
+ vga->r[1] = 4;
+ vga->m[1] = 127;
+ vga->n[1] = 31;
+ vga->f[1] = 170000000;
+ vga->apz = 64*1024*1024;
+ trace("ViRGE/GX2\n");
+ /*
+ * Memory encoding on the ViRGE/GX2 is different.
+ */
+ switch((vga->crt[0x36]>>6) & 0x03){
+
+ case 0x01:
+ vga->vmz = 4*1024*1024;
+ break;
+
+ case 0x03:
+ vga->vmz = 2*1024*1024;
+ break;
+ }
+ break;
+
+ case 0x883D: /* ViRGE/VX */
+ vga->r[1] = 4;
+ vga->m[1] = 127;
+ vga->n[1] = 31;
+ vga->f[1] = 220000000;
+ vga->apz = 64*1024*1024;
+ trace("ViRGE/VX\n");
+ /*
+ * Memory encoding on the ViRGE/VX is different.
+ */
+ vga->vmz = (2*(((vga->crt[0x36]>>5) & 0x03)+1)) * 1*1024*1024;
+ break;
+
+ case 0x8C10: /* Savage MX/MV */
+ case 0x8C12: /* Savage4/IX-MV */
+ vga->r[1] = 4;
+ vga->m[1] = 127;
+ vga->n[1] = 127;
+ vga->f[1] = 135000000; /* without clock-doubling */
+ for(i = 0x50; i < 0x70; i++)
+ vga->sequencer[i] = vgaxi(Seqx, i);
+ vga->apz = 128*1024*1024;
+ vga->vmz = savage4mem[vga->crt[0x36]>>5] * 1024 * 1024;
+ trace("Savage4/IX-MV\n");
+ break;
+
+ case 0x8C2E: /* SuperSavage/IXC16 */
+ /*
+ * This is all guessed, from the Savage4/IX,
+ * inspection of the card (apz), and web pages
+ * talking about the chip (f[1]). It seems to
+ * work on the IBM Thinkpad T23.
+ *
+ * XXX only 1024x768 works, not 1400x1050.
+ */
+ vga->r[1] = 4;
+ vga->m[1] = 127;
+ vga->n[1] = 127;
+ vga->f[1] = 135000000; /* 300000000 after doubling? */
+ for(i = 0x50; i < 0x70; i++)
+ vga->sequencer[i] = vgaxi(Seqx, i);
+ vga->apz = 64*1024*1024;
+ vga->vmz = savage4mem[vga->crt[0x36]>>5] * 1024 * 1024;
+ trace("SuperSavage/IXC16\n");
+ break;
+
+ case 0x8A22: /* Savage4 */
+ case 0x8A25: /* ProSavage PN133 */
+ case 0x8A26: /* ProSavage KN133 */
+ case 0x8D04: /* ProSavage DDR, K.Okamoto */
+ vga->r[1] = 4;
+ vga->m[1] = 511;
+ vga->n[1] = 127;
+ vga->f[1] = 300000000;
+
+ vga->apz = 128*1024*1024;
+ vga->vmz = savage4mem[vga->crt[0x36]>>5] * 1024 * 1024;
+ trace("Savage4\n");
+ break;
+ }
+
+ /*
+ * Work out the part speed-grade from name. Name can have,
+ * e.g. '-135' on the end for 135MHz part.
+ */
+ if(p = strrchr(ctlr->name, '-'))
+ vga->f[1] = strtoul(p+1, 0, 0) * 1000000;
+
+ ctlr->flag |= Fsnarf;
+}
+
+static void
+options(Vga *vga, Ctlr* ctlr)
+{
+ int id;
+
+ id = (vga->crt[0x2D]<<8)|(vga->crt[0x2E]);
+ switch(id){
+ case 0x8C2E: /* SuperSavage/IXC16 */
+ case 0x8C10: /* Savage MX/MV */
+ case 0x8C12: /* Savage4/IX-MV */
+ case 0x8A22: /* Savage4 */
+ case 0x8A25: /* ProSavage PN133 */
+ case 0x8A26: /* ProSavage KN133 */
+ case 0x8D04: /* ProSavabe DDR, K.Okamoto */
+ /*
+ * Round up so stride is multiple of 16.
+ */
+ if(vga->virtx%16)
+ vga->virtx = (vga->virtx+15)&~15;
+ break;
+ }
+
+ ctlr->flag |= Hlinear|Hpclk2x8|Henhanced|Foptions;
+}
+
+static void
+init(Vga* vga, Ctlr* ctlr)
+{
+ char *p, *val;
+ Mode *mode;
+ ulong pclk, x;
+ int id, noclockset, width;
+
+ id = (vga->crt[0x2D]<<8)|vga->crt[0x2E];
+ mode = vga->mode;
+
+ /*
+ * double 16bpp horizontal timings on ViRGE/[DG]X
+ * leaves overflow bit-fiddling to s3generic.init
+ */
+ if((id == 0x8A01) && ((mode->z+7)/8 == 2)){
+ resyncinit(vga, ctlr, Uenhanced, 0);
+ vga->crt[0x00] = ((mode->ht * 2) >> 3) - 5;
+ vga->crt[0x01] = ((mode->x * 2) >> 3) - 1;
+ vga->crt[0x02] = ((mode->shb * 2) >> 3) - 1;
+ x = (mode->ehb * 2) >> 3;
+ vga->crt[0x03] = 0x80 | (x & 0x1F);
+ vga->crt[0x04] = (mode->shs * 2) >> 3;
+ vga->crt[0x05] = ((mode->ehs * 2) >> 3) & 0x1F;
+ if(x & 0x20)
+ vga->crt[0x05] |= 0x80;
+ }
+ s3generic.init(vga, ctlr);
+
+ /*
+ * Work out the part speed-grade from name. Name can have,
+ * e.g. '-135' on the end for 135MHz part.
+ */
+ noclockset = 0;
+ if(p = strrchr(ctlr->name, '-'))
+ vga->f[1] = strtoul(p+1, 0, 0) * 1000000;
+ pclk = vga->f[1];
+
+ if(vga->mode->z > 8)
+ width = vga->virtx*(vga->mode->z/8);
+ else
+ width = vga->virtx*(8/vga->mode->z);
+
+ switch(id){
+
+ case 0x8810: /* Microsoft Virtual PC 2004 */
+ case 0x8811: /* Trio64+ */
+ /*
+ * Part comes in -135MHz speed grade. In 8-bit mode
+ * the maximum DCLK is 80MHz. In 2x8-bit mode the maximum
+ * DCLK is 135MHz using the internal clock doubler.
+ */
+ if((ctlr->flag & Hpclk2x8) && vga->mode->z == 8){
+ if(vga->f[0] > 80000000)
+ ctlr->flag |= Upclk2x8;
+ }
+ else
+ pclk = 80000000;
+
+ vga->crt[0x67] &= ~0xF2;
+ if(ctlr->flag & Upclk2x8){
+ vga->sequencer[0x15] |= 0x10;
+ vga->sequencer[0x18] |= 0x80;
+ /*
+ * There's a little strip of the border
+ * appears on the left in resolutions
+ * 1280 and above if the 0x02 bit isn't
+ * set (when it appears on the right...).
+ */
+ vga->crt[0x67] |= 0x10;
+ }
+
+ /*
+ * VLB address latch delay.
+ */
+ if((vga->crt[0x36] & 0x03) == 0x01)
+ vga->crt[0x58] &= ~0x08;
+
+ /*
+ * Display memory access control.
+ */
+ vga->crt[0x60] = 0xFF;
+
+ if(vga->mode->z > 8)
+ error("trio64: depth %d not supported\n", vga->mode->z);
+ break;
+
+ case 0x8901: /* Trio64V2 */
+ vga->crt[0x90] = 0;
+ vga->crt[0x91] = 0;
+ break;
+ case 0x8A10: /* ViRGE/GX2 */
+ vga->crt[0x90] = 0;
+
+ vga->crt[0x31] |= 0x08;
+
+ vga->crt[0x13] = (width>>3) & 0xFF;
+ vga->crt[0x51] &= ~0x30;
+ vga->crt[0x51] |= (width>>7) & 0x30;
+
+ /*
+ * Increase primary FIFO threshold
+ * to reduce flicker and tearing.
+ */
+ vga->crt[0x85] = 0x0F;
+
+ /*FALLTHROUGH*/
+ case 0x5631: /* ViRGE */
+ case 0x8A01: /* ViRGE/[DG]X */
+ if(id == 0x8A01){
+ x = mode->x * ((mode->z + 7) / 8);
+ x = (x + 7) / 8;
+ vga->crt[0x91] = x & 0xFF;
+ vga->crt[0x90] = (x >> 8) | 0x80;
+ }
+ case 0x883D: /* ViRGE/VX */
+ vga->crt[0x60] &= 0x0F;
+ /*FALLTHROUGH*/
+ case 0x8812: /* Aurora64V+ */
+ if(id == 0x8812) /* Aurora64V+ */
+ noclockset = 1;
+ vga->crt[0x65] = 0;
+ vga->crt[0x66] = 0x89;
+ vga->crt[0x67] = 0;
+
+ if(id == 0x883D){ /* ViRGE/VX */
+ /*
+ * Put the VRAM in 1-cycle EDO mode.
+ * If it is not put in this mode, hardware acceleration
+ * will leave little turds on the screen when hwfill is used.
+ */
+ vga->crt[0x36] &= ~0x0C;
+
+ if(vga->mode->x > 800 && vga->mode->z == 8)
+ vga->crt[0x67] = 0x10;
+ else
+ vga->crt[0x67] = 0;
+
+ /*
+ * Adjustments to the generic settings:
+ * heuristic fiddling.
+ *
+ * We used to set crt[0x66] to 0x89, but setting it
+ * to 0x90 seems to allow us (and more importantly the card)
+ * to access more than 2MB of memory.
+ */
+ vga->crt[0x66] = 0x90;
+ vga->crt[0x58] &= ~0x88;
+ vga->crt[0x58] |= 0x40;
+ if(vga->mode->x > 640 && vga->mode->z >= 8)
+ vga->crt[0x63] |= 0x01;
+ else
+ vga->crt[0x63] &= ~0x01;
+ }
+
+ /*
+ * The high nibble is the mode; or'ing in 0x02 turns
+ * on support for gamma correction via the DACs, but I
+ * haven't figured out how to turn on the 8-bit DACs,
+ * so gamma correction stays off.
+ */
+ switch(vga->mode->z){
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ default:
+ vga->crt[0x67] |= 0x00;
+ break;
+ case 15:
+ vga->crt[0x67] |= 0x30;
+ break;
+ case 16:
+ vga->crt[0x67] |= 0x50;
+ break;
+ case 24:
+ if(id == 0x8A10) /* GX2 has to be different */
+ vga->crt[0x67] |= 0x70;
+ else
+ vga->crt[0x67] |= 0xD0;
+ break;
+ case 32:
+ /*
+ * The ViRGE and ViRGE/VX manuals make no mention of
+ * 32-bit mode (which the GX/2 calls 24-bit unpacked mode).
+ */
+ if(id != 0x8A10)
+ error("32-bit mode only supported on the GX/2\n");
+ vga->crt[0x67] |= 0xD0;
+ break;
+ }
+
+ /*
+ * Set new MMIO method
+ */
+ vga->crt[0x53] &= ~0x18;
+ vga->crt[0x53] |= 0x08;
+
+ break;
+
+ case 0x8C2E: /* SuperSavage/IXC16 (let's try this -rsc) */
+ case 0x8C10: /* Savage MX/MV */
+ case 0x8C12: /* Savage4/IX-MV */
+ /*
+ * Experience shows the -1 (according to the manual)
+ * is incorrect.
+ */
+ x = width/8 /*-1*/;
+ vga->crt[0x91] = x;
+ vga->crt[0x90] &= ~0x07;
+ vga->crt[0x90] |= (x>>8) & 0x07;
+
+ case 0x8D04: /* ProSavage DDR, K.Okamoto */
+ x = mode->x * ((mode->z + 7) / 8);
+ x = (x + 7) / 8;
+ vga->crt[0x91] = x & 0xFF;
+ vga->crt[0x90] = (x >> 8) | 0x80;
+
+ /*FALLTHROUGH*/
+
+ case 0x8A22: /* Savage4 */
+ case 0x8A25: /* ProSavage PN133 */
+ case 0x8A26: /* ProSavage KN133 */
+ /*
+ * The Savage 4 is frustratingly similar to the
+ * ViRGE/GX2, but has enough slight differences
+ * to warrant special treatment. Blog.
+ */
+ vga->crt[0x66] = 0x89;
+ vga->crt[0x67] = 0;
+ vga->crt[0x85] = 0x02;
+ vga->crt[0x31] |= 0x08;
+
+ vga->crt[0x13] = (width>>3) & 0xFF;
+ vga->crt[0x51] &= ~0x30;
+ vga->crt[0x51] |= (width>>7) & 0x30;
+
+ /* pull screen width from GBD for graphics engine. */
+ vga->crt[0x50] = 0xC1; /* set color mode */
+
+ /*
+ * The high nibble is the mode; or'ing in 0x02 turns
+ * on support for gamma correction via the DACs, but I
+ * haven't figured out how to turn on the 8-bit DACs,
+ * so gamma correction stays off.
+ */
+ switch(vga->mode->z){
+ default:
+ error("%d-bit mode not supported on savage 4\n", vga->mode->z);
+ case 8:
+ vga->crt[0x67] |= 0x00;
+ vga->crt[0x50] |= 0<<4;
+ break;
+ case 15:
+ vga->crt[0x67] |= 0x20;
+ vga->crt[0x50] |= 1<<4;
+ break;
+ case 16:
+ vga->crt[0x67] |= 0x40;
+ vga->crt[0x50] |= 1<<4;
+ /*
+ * Manual says this should be accompanied by setting
+ * the clock-doubled modes but this seems to be the
+ * right answer.
+ * Should check if using doubled modes tidies any of
+ * this up.
+ */
+ if(id == 0x8C12 || id == 0x8C2E || id == 0x8C10)
+ vga->crt[0x67] |= 0x10;
+ break;
+ case 32:
+ vga->crt[0x67] |= 0xD0;
+ vga->crt[0x50] |= 3<<4;
+ break;
+ }
+ break;
+ }
+
+ /*
+ * Clock bits. If the desired video clock is
+ * one of the two standard VGA clocks it can just be
+ * set using bits <3:2> of vga->misc, otherwise we
+ * need to programme the DCLK PLL.
+ */
+ if(val = dbattr(vga->mode->attr, "noclockset")){
+ if((noclockset = strtol(val, &p, 0)) == 0 && p == val)
+ error("%s: invalid 'noclockset' attr\n", ctlr->name);
+ }
+ if(vga->f[0] == 0)
+ vga->f[0] = vga->mode->frequency;
+ vga->misc &= ~0x0C;
+ if(vga->f[0] == VgaFreq0){
+ /* nothing to do */;
+ }
+ else if(vga->f[0] == VgaFreq1)
+ vga->misc |= 0x04;
+ else if(noclockset){
+ /*
+ * Don't touch the clock on the Aurora64V+
+ * and optionally on some others.
+ */
+ vga->misc |= 0x0C;
+ }
+ else{
+ if(vga->f[0] > pclk)
+ error("%s: invalid pclk - %lud\n",
+ ctlr->name, vga->f[0]);
+
+ trio64clock(vga, ctlr);
+ switch(id){
+
+ case 0x8A10: /* ViRGE/GX2 */
+ vga->sequencer[0x12] = (vga->r[0]<<6)|vga->n[0];
+ if(vga->r[0] & 0x04)
+ vga->sequencer[0x29] |= 0x01;
+ else
+ vga->sequencer[0x29] &= ~0x01;
+ break;
+
+ case 0x8C2E: /* SuperSavage/IXC16 (let's try this -rsc) */
+ case 0x8C10: /* Savage MX/MV */
+ case 0x8C12: /* Savage4/IX-MV */
+ case 0x8A22: /* Savage4 */
+ case 0x8A25: /* ProSavage PN133 */
+ case 0x8A26: /* ProSavage KN133 */
+ case 0x8D04: /* ProSavage DDR, K.Okamoto */
+ vga->sequencer[0x12] = (vga->r[0]<<6)|(vga->n[0] & 0x3F);
+ vga->sequencer[0x39] &= ~0x01;
+ vga->sequencer[0x29] &= ~0x1C;
+ if(vga->r[0] & 0x04)
+ vga->sequencer[0x29] |= (1<<2);
+ if(vga->m[0] & 0x100)
+ vga->sequencer[0x29] |= (1<<3);
+ if(vga->n[0] & 0x40)
+ vga->sequencer[0x29] |= (1<<4);
+ break;
+
+ default:
+ vga->sequencer[0x12] = (vga->r[0]<<5)|vga->n[0];
+ break;
+ }
+ vga->sequencer[0x13] = vga->m[0];
+ vga->misc |= 0x0C;
+ }
+
+ /*
+ * Internal clock generator.
+ */
+ vga->sequencer[0x15] &= ~0x31;
+ vga->sequencer[0x15] |= 0x02;
+ vga->sequencer[0x18] &= ~0x80;
+
+ /*
+ * Start display FIFO fetch.
+ */
+ x = (vga->crt[0]+vga->crt[4]+1)/2;
+ vga->crt[0x3B] = x;
+ if(x & 0x100)
+ vga->crt[0x5D] |= 0x40;
+
+ /*
+ * Display memory access control.
+ * Calculation of the M-parameter (Crt54) is
+ * memory-system and dot-clock dependent, the
+ * values below are guesses from dumping
+ * registers.
+ * The Savage4 does not document 0x54,
+ * but we leave this anyway.
+ */
+ if(vga->mode->x <= 800)
+ vga->crt[0x54] = 0xE8;
+ else if(vga->mode->x <= 1024 && id != 0x8C12 && id != 0x8C2E)
+ vga->crt[0x54] = 0xA8;
+ else
+ vga->crt[0x54] = 0x00/*0x48*/;
+
+ ctlr->flag |= Finit;
+}
+
+static void
+load(Vga* vga, Ctlr* ctlr)
+{
+ int id;
+ ushort advfunc;
+
+ s3generic.load(vga, ctlr);
+
+ /*
+ * Load the PLL registers if necessary.
+ * Not sure if the variable-delay method of setting the
+ * PLL will work without a write here to vga->misc,
+ * so use the immediate-load method by toggling bit 5
+ * of Seq15 if necessary.
+ */
+ vgaxo(Seqx, 0x12, vga->sequencer[0x12]);
+ vgaxo(Seqx, 0x13, vga->sequencer[0x13]);
+ id = (vga->crt[0x2D]<<8)|vga->crt[0x2E];
+ switch(id){
+ case 0x883D: /* ViRGE/VX*/
+ vgaxo(Crtx, 0x36, vga->crt[0x36]);
+ break;
+ case 0x8A10: /* ViRGE/GX2 */
+ vgaxo(Seqx, 0x29, vga->sequencer[0x29]);
+ break;
+ case 0x8C2E: /* SuperSavage/IXC16 (let's try this -rsc) */
+ case 0x8C12: /* Savage4/IX-MV */
+ vgaxo(Crtx, 0x90, vga->crt[0x90]);
+ vgaxo(Crtx, 0x91, vga->crt[0x91]);
+ /*FALLTHROUGH*/
+ case 0x8A22: /* Savage4 */
+ case 0x8A25: /* ProSavage PN133 */
+ case 0x8A26: /* ProSavage KN133 */
+ case 0x8D04: /* ProSavage DDR, K.Okamoto */
+ vgaxo(Seqx, 0x29, vga->sequencer[0x29]);
+ vgaxo(Seqx, 0x39, vga->sequencer[0x39]);
+ break;
+ }
+ if((vga->misc & 0x0C) == 0x0C)
+ vgaxo(Seqx, 0x15, vga->sequencer[0x15]|0x20);
+ vgaxo(Seqx, 0x15, vga->sequencer[0x15]);
+ vgaxo(Seqx, 0x18, vga->sequencer[0x18]);
+
+ vgaxo(Crtx, 0x60, vga->crt[0x60]);
+ vgaxo(Crtx, 0x63, vga->crt[0x63]);
+ vgaxo(Crtx, 0x65, vga->crt[0x65]);
+ vgaxo(Crtx, 0x66, vga->crt[0x66]);
+ vgaxo(Crtx, 0x67, vga->crt[0x67]);
+
+ switch(id){
+
+ case 0x8810: /* Microsoft Virtual PC 2004 */
+ case 0x8811: /* Trio64+ */
+ advfunc = 0x0000;
+ if(ctlr->flag & Uenhanced)
+ advfunc = 0x0001;
+ outportw(0x4AE8, advfunc);
+ break;
+ case 0x8901: /* Trio64V2 */
+ case 0x8A01: /* ViRGE/[DG]X */
+ vgaxo(Crtx, 0x90, vga->crt[0x90]);
+ vgaxo(Crtx, 0x91, vga->crt[0x91]);
+ break;
+ case 0x8A10: /* ViRGE/GX2 */
+ vgaxo(Crtx, 0x90, vga->crt[0x90]);
+ vgaxo(Crtx, 0x31, vga->crt[0x31]);
+ vgaxo(Crtx, 0x13, vga->crt[0x13]);
+ vgaxo(Crtx, 0x51, vga->crt[0x51]);
+ vgaxo(Crtx, 0x85, vga->crt[0x85]);
+ break;
+ case 0x8D04: /* ProSavage DDR, K.Okamoto */
+ vgaxo(Crtx, 0x90, vga->crt[0x90]); //K.Okamoto
+ vgaxo(Crtx, 0x91, vga->crt[0x91]); //K.Okamoto
+ case 0x8C2E: /* SuperSavage/IXC16 (let's try this -rsc) */
+ case 0x8C12: /* Savage4/IX-MV */
+ case 0x8A22: /* Savage4 */
+ case 0x8A25: /* ProSavage PN133 */
+ case 0x8A26: /* ProSavage KN133 */
+ vgaxo(Crtx, 0x31, vga->crt[0x31]);
+ vgaxo(Crtx, 0x13, vga->crt[0x13]);
+ vgaxo(Crtx, 0x51, vga->crt[0x51]);
+ vgaxo(Crtx, 0x85, vga->crt[0x85]);
+ vgaxo(Crtx, 0x50, vga->crt[0x50]);
+ break;
+ }
+}
+
+static void
+dump(Vga* vga, Ctlr* ctlr)
+{
+ int i, id;
+ ulong dclk, m, n, r;
+
+ s3generic.dump(vga, ctlr);
+ printitem(ctlr->name, "Crt70");
+ for(i = 0x70; i < 0x99; i++)
+ printreg(vga->crt[i]);
+
+ printitem(ctlr->name, "Seq08");
+ for(i = 0x08; i < 0x10; i++)
+ printreg(vga->sequencer[i]);
+ printitem(ctlr->name, "Seq10");
+ for(i = 0x10; i < 0x50; i++)
+ printreg(vga->sequencer[i]);
+ id = (vga->crt[0x2D]<<8)|vga->crt[0x2E];
+ switch(id){
+ default:
+ break;
+
+ case 0x8812: /* Aurora64V+ */
+ case 0x8C2E: /* SuperSavage/IXC16 (let's try this -rsc) */
+ case 0x8C12: /* Savage4/IX-MV */
+ printitem(ctlr->name, "Seq50");
+ for(i = 0x50; i < 0x70; i++)
+ printreg(vga->sequencer[i]);
+ break;
+ }
+
+ printitem(ctlr->name, "Crt2D");
+ printreg(vga->crt[0x2D]);
+ printreg(vga->crt[0x2E]);
+ printreg(vga->crt[0x2F]);
+
+ m = vga->sequencer[0x13] & vga->m[1];
+ n = vga->sequencer[0x12] & vga->n[1];
+ r = (vga->sequencer[0x12]>>5) & 0x03;
+
+ switch(id){
+ case 0x8812: /* Aurora64V+ */
+ r = (vga->sequencer[0x12]>>6) & 0x03;
+ break;
+ case 0x8A01: /* ViRGE/[DG]X */
+ r = (vga->sequencer[0x12]>>5) & 0x07;
+ break;
+ case 0x8A10: /* ViRGE/GX2 */
+ r = (vga->sequencer[0x12]>>6) & 0x03;
+ r |= (vga->sequencer[0x29] & 0x01)<<2;
+ break;
+ case 0x8C2E: /* SuperSavage/IXC16 (let's try this -rsc) */
+ case 0x8C12: /* Savage4/IX-MV */
+ case 0x8A22: /* Savage4 */
+ case 0x8A25: /* ProSavage PN133 */
+ case 0x8A26: /* ProSavage KN133 */
+ case 0x8D04: /* Prosavage DDR, K.Okamoto */
+ m = vga->sequencer[0x13] & 0xFF;
+ if(vga->sequencer[0x29] & (1<<3))
+ m |= 0x100;
+ if(vga->sequencer[0x29] & (1<<4))
+ n |= 0x40;
+ r = (vga->sequencer[0x12]>>6) & 0x03;
+ r |= (vga->sequencer[0x29] & (1<<2));
+ break;
+ }
+
+ dclk = (m+2)*RefFreq;
+ dclk /= (n+2)*(1<<r);
+ printitem(ctlr->name, "dclk m n r");
+ Bprint(&stdout, "%9ld %8ld - %8ld %8ld\n", dclk, m, n, r);
+
+ m = vga->sequencer[0x11] & 0x7F;
+ n = vga->sequencer[0x10] & 0x1F;
+ r = (vga->sequencer[0x10]>>5) & 0x03; /* might be GX/2 specific */
+ dclk = (m+2)*RefFreq;
+ dclk /= (n+2)*(1<<r);
+ printitem(ctlr->name, "mclk m n r");
+ Bprint(&stdout, "%9ld %8ld - %8ld %8ld\n", dclk, m, n, r);
+}
+
+Ctlr virge = {
+ "virge", /* name */
+ snarf, /* snarf */
+ options, /* options */
+ init, /* init */
+ load, /* load */
+ dump, /* dump */
+};