743 lines
26 KiB
C
743 lines
26 KiB
C
#include <stdlib.h>
|
|
#include "ibm.h"
|
|
#include "mem.h"
|
|
#include "pci.h"
|
|
#include "vid_voodoo.h"
|
|
|
|
static int tris = 0;
|
|
|
|
static struct voodoo
|
|
{
|
|
mem_mapping_t mmio_mapping;
|
|
mem_mapping_t fb_mapping;
|
|
mem_mapping_t tex_mapping;
|
|
|
|
int pci_enable;
|
|
|
|
uint32_t color0, color1;
|
|
|
|
uint8_t dac_data[8];
|
|
int dac_reg;
|
|
uint8_t dac_readdata;
|
|
|
|
uint32_t dRdX, dGdX, dBdX, dZdX, dAdX, dSdX, dTdX, dWdX;
|
|
|
|
uint32_t dRdY, dGdY, dBdY, dZdY, dAdY, dSdY, dTdY, dWdY;
|
|
|
|
uint32_t fbiInit0, fbiInit1, fbiInit2, fbiInit3, fbiInit4;
|
|
|
|
uint32_t fbzMode;
|
|
|
|
uint8_t initEnable;
|
|
|
|
uint32_t lfbMode;
|
|
|
|
uint32_t memBaseAddr;
|
|
|
|
uint32_t startR, startG, startB, startZ, startA, startS, startT, startW;
|
|
|
|
uint32_t vertexAx, vertexAy, vertexBx, vertexBy, vertexCx, vertexCy;
|
|
|
|
uint32_t front_offset, back_offset, aux_offset;
|
|
|
|
uint32_t fb_read_offset, fb_write_offset;
|
|
|
|
uint32_t draw_offset;
|
|
|
|
int row_width;
|
|
|
|
uint8_t *fb_mem, *tex_mem;
|
|
} voodoo;
|
|
|
|
enum
|
|
{
|
|
SST_status = 0x000,
|
|
|
|
SST_vertexAx = 0x008,
|
|
SST_vertexAy = 0x00c,
|
|
SST_vertexBx = 0x010,
|
|
SST_vertexBy = 0x014,
|
|
SST_vertexCx = 0x018,
|
|
SST_vertexCy = 0x01c,
|
|
|
|
SST_startR = 0x0020,
|
|
SST_startG = 0x0024,
|
|
SST_startB = 0x0028,
|
|
SST_startZ = 0x002c,
|
|
SST_startA = 0x0030,
|
|
SST_startS = 0x0034,
|
|
SST_startT = 0x0038,
|
|
SST_startW = 0x003c,
|
|
|
|
SST_dRdX = 0x0040,
|
|
SST_dGdX = 0x0044,
|
|
SST_dBdX = 0x0048,
|
|
SST_dZdX = 0x004c,
|
|
SST_dAdX = 0x0050,
|
|
SST_dSdX = 0x0054,
|
|
SST_dTdX = 0x0058,
|
|
SST_dWdX = 0x005c,
|
|
|
|
SST_dRdY = 0x0060,
|
|
SST_dGdY = 0x0064,
|
|
SST_dBdY = 0x0068,
|
|
SST_dZdY = 0x006c,
|
|
SST_dAdY = 0x0070,
|
|
SST_dSdY = 0x0074,
|
|
SST_dTdY = 0x0078,
|
|
SST_dWdY = 0x007c,
|
|
|
|
SST_triangleCMD = 0x0080,
|
|
|
|
SST_fbzMode = 0x110,
|
|
SST_lfbMode = 0x114,
|
|
SST_swapbufferCMD = 0x128,
|
|
|
|
SST_color0 = 0x144,
|
|
SST_color1 = 0x148,
|
|
|
|
SST_fbiInit4 = 0x200,
|
|
SST_fbiInit0 = 0x210,
|
|
SST_fbiInit1 = 0x214,
|
|
SST_fbiInit2 = 0x218,
|
|
SST_fbiInit3 = 0x21c,
|
|
SST_dacData = 0x22c
|
|
};
|
|
|
|
enum
|
|
{
|
|
LFB_WRITE_FRONT = 0x0000,
|
|
LFB_WRITE_BACK = 0x0010,
|
|
LFB_WRITE_MASK = 0x0030
|
|
};
|
|
|
|
enum
|
|
{
|
|
LFB_READ_FRONT = 0x0000,
|
|
LFB_READ_BACK = 0x0040,
|
|
LFB_READ_AUX = 0x0080,
|
|
LFB_READ_MASK = 0x00c0
|
|
};
|
|
|
|
enum
|
|
{
|
|
LFB_FORMAT_RGB565 = 0,
|
|
LFB_FORMAT_DEPTH = 15,
|
|
LFB_FORMAT_MASK = 15
|
|
};
|
|
|
|
enum
|
|
{
|
|
LFB_WRITE_COLOUR = 1,
|
|
LFB_WRITE_DEPTH = 2
|
|
};
|
|
|
|
enum
|
|
{
|
|
FBZ_DITHER = 0x100,
|
|
FBZ_DRAWRGB = 0x200,
|
|
|
|
FBZ_DRAW_FRONT = 0x0000,
|
|
FBZ_DRAW_BACK = 0x4000,
|
|
FBZ_DRAW_MASK = 0xc000
|
|
};
|
|
|
|
static int voodoo_reads = 0;
|
|
|
|
static void voodoo_recalc()
|
|
{
|
|
uint32_t buffer_offset = ((voodoo.fbiInit2 >> 11) & 511) * 4096;
|
|
|
|
voodoo.front_offset = 0;
|
|
voodoo.back_offset = buffer_offset;
|
|
voodoo.aux_offset = buffer_offset * 2;
|
|
|
|
switch (voodoo.lfbMode & LFB_WRITE_MASK)
|
|
{
|
|
case LFB_WRITE_FRONT:
|
|
voodoo.fb_write_offset = voodoo.front_offset;
|
|
break;
|
|
case LFB_WRITE_BACK:
|
|
voodoo.fb_write_offset = voodoo.back_offset;
|
|
break;
|
|
|
|
default:
|
|
fatal("voodoo_recalc : unknown lfb destination\n");
|
|
}
|
|
|
|
switch (voodoo.lfbMode & LFB_READ_MASK)
|
|
{
|
|
case LFB_READ_FRONT:
|
|
voodoo.fb_read_offset = voodoo.front_offset;
|
|
break;
|
|
case LFB_READ_BACK:
|
|
voodoo.fb_read_offset = voodoo.back_offset;
|
|
break;
|
|
case LFB_READ_AUX:
|
|
voodoo.fb_read_offset = voodoo.aux_offset;
|
|
break;
|
|
|
|
default:
|
|
fatal("voodoo_recalc : unknown lfb source\n");
|
|
}
|
|
|
|
switch (voodoo.fbzMode & FBZ_DRAW_MASK)
|
|
{
|
|
case FBZ_DRAW_FRONT:
|
|
voodoo.draw_offset = voodoo.front_offset;
|
|
break;
|
|
case FBZ_DRAW_BACK:
|
|
voodoo.draw_offset = voodoo.back_offset;
|
|
break;
|
|
|
|
default:
|
|
fatal("voodoo_recalc : unknown draw buffer\n");
|
|
}
|
|
|
|
voodoo.row_width = ((voodoo.fbiInit1 >> 4) & 15) * 64 * 2;
|
|
pclog("voodoo_recalc : front_offset %08X back_offset %08X aux_offset %08X\n", voodoo.front_offset, voodoo.back_offset, voodoo.aux_offset);
|
|
pclog(" fb_read_offset %08X fb_write_offset %08X row_width %i\n", voodoo.fb_read_offset, voodoo.fb_write_offset, voodoo.row_width);
|
|
}
|
|
|
|
static int dither_matrix_4x4[16] =
|
|
{
|
|
0, 8, 2, 10,
|
|
12, 4, 14, 6,
|
|
3, 11, 1, 9,
|
|
15, 7, 13, 5
|
|
};
|
|
|
|
static int dither_rb[256][4][4];
|
|
static int dither_g[256][4][4];
|
|
|
|
static void voodoo_make_dither()
|
|
{
|
|
int c, x, y;
|
|
int seen_rb[1024];
|
|
int seen_g[1024];
|
|
|
|
for (c = 0; c < 256; c++)
|
|
{
|
|
int rb = (int)(((double)c * 496.0) / 256.0);
|
|
int g = (int)(((double)c * 1008.0) / 256.0);
|
|
pclog("rb %i %i\n", rb, c);
|
|
for (y = 0; y < 4; y++)
|
|
{
|
|
for (x = 0; x < 4; x++)
|
|
{
|
|
int val;
|
|
|
|
val = rb + dither_matrix_4x4[x + (y << 2)];
|
|
dither_rb[c][y][x] = val >> 4;
|
|
pclog("RB %i %i, %i %i %i %i\n", c, x, y, val, val >> 4, dither_rb[c][y][x]);
|
|
|
|
if (dither_rb[c][y][x] > 31)
|
|
fatal("RB overflow %i %i %i %i\n", c, x, y, dither_rb[c][y][x]);
|
|
|
|
val = g + dither_matrix_4x4[x + (y << 2)];
|
|
dither_g[c][y][x] = val >> 4;
|
|
|
|
if (dither_g[c][y][x] > 63)
|
|
fatal("G overflow %i %i %i %i\n", c, x, y, dither_g[c][y][x]);
|
|
}
|
|
}
|
|
}
|
|
|
|
memset(seen_rb, 0, sizeof(seen_rb));
|
|
memset(seen_g, 0, sizeof(seen_g));
|
|
|
|
for (c = 0; c < 256; c++)
|
|
{
|
|
int total_rb = 0;
|
|
int total_g = 0;
|
|
for (y = 0; y < 4; y++)
|
|
{
|
|
for (x = 0; x < 4; x++)
|
|
{
|
|
total_rb += dither_rb[c][y][x];
|
|
pclog("total_rb %i %i, %i %i %i\n", c, x, y, total_rb, dither_rb[c][y][x]);
|
|
total_g += dither_g[c][y][x];
|
|
}
|
|
}
|
|
|
|
if (seen_rb[total_rb])
|
|
fatal("Duplicate rb %i %i\n", c, total_rb);
|
|
seen_rb[total_rb] = 1;
|
|
|
|
if (seen_g[total_g])
|
|
fatal("Duplicate g %i %i\n", c, total_g);
|
|
seen_g[total_g] = 1;
|
|
}
|
|
}
|
|
|
|
static void voodoo_triangle(struct voodoo *voodoo)
|
|
{
|
|
int y, yend, ydir;
|
|
int xstart, xend, xdir;
|
|
int dx1, dx2;
|
|
|
|
pclog("voodoo_triangle %i : vA %f, %f vB %f, %f vC %f, %f\n", tris, (float)voodoo->vertexAx / 16.0, (float)voodoo->vertexAy / 16.0,
|
|
(float)voodoo->vertexBx / 16.0, (float)voodoo->vertexBy / 16.0,
|
|
(float)voodoo->vertexCx / 16.0, (float)voodoo->vertexCy / 16.0);
|
|
// output = 3;
|
|
tris++;
|
|
// if (tris == 3)
|
|
// fatal("tris 2\n");
|
|
|
|
y = voodoo->vertexAy >> 4;
|
|
ydir = (voodoo->vertexAy >= voodoo->vertexCy) ? -1 : 1;
|
|
|
|
if (voodoo->vertexAy == voodoo->vertexBy)
|
|
{
|
|
xstart = voodoo->vertexAx << 8;
|
|
xend = voodoo->vertexBx << 8;
|
|
}
|
|
else
|
|
xstart = xend = voodoo->vertexAx << 8;
|
|
xdir = (xstart >= xend) ? -1 : 1;
|
|
|
|
if (voodoo->vertexAy != voodoo->vertexBy)
|
|
{
|
|
/*Draw top half*/
|
|
dx1 = (int)(((voodoo->vertexBx << 8) - xstart) << 4) / (int)((voodoo->vertexBy - voodoo->vertexAy) * ydir);
|
|
dx2 = (int)(((voodoo->vertexCx << 8) - xend) << 4) / (int)((voodoo->vertexCy - voodoo->vertexAy) * ydir);
|
|
yend = voodoo->vertexBy >> 4;
|
|
|
|
pclog("voodoo_triangle : top-half %X %X %X %X %i %i %i %i\n", xstart, xend, dx1, dx2, xdir, y, yend, ydir);
|
|
|
|
for (; y != yend; y += ydir)
|
|
{
|
|
pclog(" %i : %i - %i\n", xstart >> 12, xend >> 12);
|
|
xstart += dx1;
|
|
xend += dx2;
|
|
}
|
|
}
|
|
|
|
|
|
if (voodoo->vertexBy != voodoo->vertexCy)
|
|
{
|
|
/*Draw bottom half*/
|
|
dx1 = (int)(((voodoo->vertexCx << 8) - xstart) << 4) / (int)((voodoo->vertexCy - voodoo->vertexAy) * ydir);
|
|
dx2 = (int)(((voodoo->vertexCx << 8) - xend) << 4) / (int)((voodoo->vertexCy - voodoo->vertexAy) * ydir);
|
|
yend = voodoo->vertexCy >> 4;
|
|
|
|
pclog("voodoo_triangle : bottom-half %X %X %X %X %X %i %i %i %i\n", xstart, xend, dx1, dx2, dx2 * 36, xdir, y, yend, ydir);
|
|
|
|
for (; y != yend; y += ydir)
|
|
{
|
|
int x = xstart >> 12, x2 = xend >> 12;
|
|
pclog(" %i : %i - %i\n", y, x, x2);
|
|
|
|
for (; x != x2; x += xdir)
|
|
{
|
|
if (voodoo->fbzMode & FBZ_DRAWRGB)
|
|
{
|
|
int r = (voodoo->color1 >> 16) & 0xff;
|
|
int g = (voodoo->color1 >> 8) & 0xff;
|
|
int b = voodoo->color1 & 0xff;
|
|
if (voodoo->fbzMode & FBZ_DITHER)
|
|
{
|
|
r = dither_rb[r][y & 3][x & 3];
|
|
g = dither_g[g][y & 3][x & 3];
|
|
b = dither_rb[b][y & 3][x & 3];
|
|
/* r = ((r << 1) + dither_matrix_4x4[(x & 3) + ((y & 3) << 2)]) >> 4;
|
|
g = ((g << 2) + dither_matrix_4x4[(x & 3) + ((y & 3) << 2)]) >> 4;
|
|
b = ((b << 1) + dither_matrix_4x4[(x & 3) + ((y & 3) << 2)]) >> 4;
|
|
if (r > 31) r = 31;
|
|
if (g > 63) g = 63;
|
|
if (b > 31) b = 31;*/
|
|
/* r = (((r << 1) - (r >> 4) + (r >> 7) + dither_matrix_4x4[(x & 3) + ((y & 3) << 2)]) >> 1) >> 3;
|
|
g = (((g << 2) - (g >> 4) + (g >> 6) + dither_matrix_4x4[(x & 3) + ((y & 3) << 2)]) >> 2) >> 2;
|
|
b = (((b << 1) - (b >> 4) + (b >> 7) + dither_matrix_4x4[(x & 3) + ((y & 3) << 2)]) >> 1) >> 3;*/
|
|
}
|
|
else
|
|
{
|
|
r >>= 3;
|
|
g >>= 2;
|
|
b >>= 3;
|
|
}
|
|
*(uint16_t *)(&voodoo->fb_mem[voodoo->draw_offset + (y * voodoo->row_width) + (x << 1)]) = b | (g << 5) | (r << 11);
|
|
pclog(" %i = %i %i %i %04X %08X %08X\n", x, r, g, b, b | (g << 5) | (r << 11), voodoo->draw_offset + (y * voodoo->row_width) + (x << 1), *(uint32_t *)(&voodoo->fb_mem[4]));
|
|
}
|
|
}
|
|
xstart += dx1;
|
|
xend += dx2;
|
|
}
|
|
}
|
|
|
|
/* for (y = ystart, y != yend; y += ydir)
|
|
{
|
|
if (voodoo.fbzMode & FBZ_DITHER
|
|
}*/
|
|
}
|
|
|
|
static uint32_t voodoo_readl(uint32_t addr, void *priv)
|
|
{
|
|
uint32_t temp;
|
|
switch (addr & 0x3fc)
|
|
{
|
|
case SST_status:
|
|
temp = 0x0ffff03f; /*FIFOs empty*/
|
|
break;
|
|
|
|
case SST_lfbMode:
|
|
return voodoo.lfbMode;
|
|
|
|
case SST_fbiInit4:
|
|
temp = voodoo.fbiInit4;
|
|
break;
|
|
case SST_fbiInit0:
|
|
temp = voodoo.fbiInit0;
|
|
break;
|
|
case SST_fbiInit1:
|
|
temp = voodoo.fbiInit1 & ~5; /*Pass-thru board with one SST-1*/
|
|
break;
|
|
case SST_fbiInit2:
|
|
if (voodoo.initEnable & 0x04)
|
|
temp = voodoo.dac_readdata;
|
|
else
|
|
temp = voodoo.fbiInit2;
|
|
break;
|
|
case SST_fbiInit3:
|
|
temp = voodoo.fbiInit3;
|
|
break;
|
|
|
|
default:
|
|
fatal("voodoo_readl : bad addr %08X\n", addr);
|
|
temp = 0xffffffff;
|
|
}
|
|
pclog("voodoo_readl : addr %08X val %08X %04X(%08X):%08X %i\n", addr, temp, CS, cs, pc, voodoo_reads++);
|
|
// if (voodoo_reads == 200494)
|
|
// output = 3;
|
|
return temp;
|
|
}
|
|
|
|
static void voodoo_writel(uint32_t addr, uint32_t val, void *priv)
|
|
{
|
|
pclog("voodoo_writel : addr %08X val %08X %04X(%08X):%08X\n", addr, val, CS, cs, pc);
|
|
switch (addr & 0x3fc)
|
|
{
|
|
case SST_swapbufferCMD:
|
|
pclog(" start swap buffer command\n");
|
|
// output = 3;
|
|
break;
|
|
|
|
case SST_vertexAx:
|
|
voodoo.vertexAx = val & 0xffff;
|
|
break;
|
|
case SST_vertexAy:
|
|
voodoo.vertexAy = val & 0xffff;
|
|
break;
|
|
case SST_vertexBx:
|
|
voodoo.vertexBx = val & 0xffff;
|
|
break;
|
|
case SST_vertexBy:
|
|
voodoo.vertexBy = val & 0xffff;
|
|
break;
|
|
case SST_vertexCx:
|
|
voodoo.vertexCx = val & 0xffff;
|
|
break;
|
|
case SST_vertexCy:
|
|
voodoo.vertexCy = val & 0xffff;
|
|
break;
|
|
|
|
case SST_startR:
|
|
voodoo.startR = val & 0xffffff;
|
|
break;
|
|
case SST_startG:
|
|
voodoo.startG = val & 0xffffff;
|
|
break;
|
|
case SST_startB:
|
|
voodoo.startB = val & 0xffffff;
|
|
break;
|
|
case SST_startZ:
|
|
voodoo.startZ = val;
|
|
break;
|
|
case SST_startA:
|
|
voodoo.startA = val & 0xffffff;
|
|
break;
|
|
case SST_startS:
|
|
voodoo.startS = val;
|
|
break;
|
|
case SST_startT:
|
|
voodoo.startT = val;
|
|
break;
|
|
case SST_startW:
|
|
voodoo.startW = val;
|
|
break;
|
|
|
|
case SST_dRdX:
|
|
voodoo.dRdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
|
|
break;
|
|
case SST_dGdX:
|
|
voodoo.dGdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
|
|
break;
|
|
case SST_dBdX:
|
|
voodoo.dBdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
|
|
break;
|
|
case SST_dZdX:
|
|
voodoo.dZdX = val;
|
|
break;
|
|
case SST_dAdX:
|
|
voodoo.dAdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
|
|
break;
|
|
case SST_dSdX:
|
|
voodoo.dSdX = val;
|
|
break;
|
|
case SST_dTdX:
|
|
voodoo.dTdX = val;
|
|
break;
|
|
case SST_dWdX:
|
|
voodoo.dWdX = val;
|
|
break;
|
|
|
|
case SST_dRdY:
|
|
voodoo.dRdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
|
|
break;
|
|
case SST_dGdY:
|
|
voodoo.dGdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
|
|
break;
|
|
case SST_dBdY:
|
|
voodoo.dBdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
|
|
break;
|
|
case SST_dZdY:
|
|
voodoo.dZdY = val;
|
|
break;
|
|
case SST_dAdY:
|
|
voodoo.dAdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
|
|
break;
|
|
case SST_dSdY:
|
|
voodoo.dSdY = val;
|
|
break;
|
|
case SST_dTdY:
|
|
voodoo.dTdY = val;
|
|
break;
|
|
case SST_dWdY:
|
|
voodoo.dWdY = val;
|
|
break;
|
|
|
|
case SST_triangleCMD:
|
|
voodoo_triangle(&voodoo);
|
|
break;
|
|
|
|
|
|
case SST_fbzMode:
|
|
voodoo.fbzMode = val;
|
|
break;
|
|
case SST_lfbMode:
|
|
voodoo.lfbMode = val;
|
|
voodoo_recalc();
|
|
break;
|
|
|
|
case SST_color0:
|
|
voodoo.color0 = val;
|
|
break;
|
|
case SST_color1:
|
|
voodoo.color1 = val;
|
|
break;
|
|
|
|
case SST_fbiInit4:
|
|
if (voodoo.initEnable & 0x01)
|
|
voodoo.fbiInit4 = val;
|
|
break;
|
|
case SST_fbiInit0:
|
|
if (voodoo.initEnable & 0x01)
|
|
voodoo.fbiInit0 = val;
|
|
break;
|
|
case SST_fbiInit1:
|
|
if (voodoo.initEnable & 0x01)
|
|
voodoo.fbiInit1 = val;
|
|
break;
|
|
case SST_fbiInit2:
|
|
if (voodoo.initEnable & 0x01)
|
|
{
|
|
voodoo.fbiInit2 = val;
|
|
voodoo_recalc();
|
|
}
|
|
break;
|
|
case SST_fbiInit3:
|
|
if (voodoo.initEnable & 0x01)
|
|
voodoo.fbiInit3 = val;
|
|
break;
|
|
|
|
case SST_dacData:
|
|
voodoo.dac_reg = (val >> 8) & 7;
|
|
voodoo.dac_readdata = 0xff;
|
|
if (val & 0x800)
|
|
{
|
|
pclog(" dacData read %i %02X\n", voodoo.dac_reg, voodoo.dac_data[7]);
|
|
if (voodoo.dac_reg == 5)
|
|
{
|
|
switch (voodoo.dac_data[7])
|
|
{
|
|
case 0x01: voodoo.dac_readdata = 0x55; break;
|
|
case 0x07: voodoo.dac_readdata = 0x71; break;
|
|
case 0x0b: voodoo.dac_readdata = 0x79; break;
|
|
}
|
|
}
|
|
else
|
|
voodoo.dac_readdata = voodoo.dac_data[voodoo.dac_readdata];
|
|
}
|
|
else
|
|
voodoo.dac_data[voodoo.dac_reg] = val & 0xff;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static uint16_t voodoo_fb_readw(uint32_t addr, void *priv)
|
|
{
|
|
pclog("voodoo_fb_readw : %08X %04X\n", addr, *(uint16_t *)(&voodoo.fb_mem[addr & 0x1fffff]));
|
|
return *(uint16_t *)(&voodoo.fb_mem[addr & 0x1fffff]);
|
|
}
|
|
static uint32_t voodoo_fb_readl(uint32_t addr, void *priv)
|
|
{
|
|
int x, y;
|
|
uint32_t read_addr;
|
|
uint32_t temp;
|
|
|
|
x = (addr >> 1) & 0x3ff;
|
|
y = (addr >> 11) & 0x3ff;
|
|
read_addr = voodoo.fb_read_offset + (x << 1) + (y * voodoo.row_width);
|
|
|
|
temp = *(uint32_t *)(&voodoo.fb_mem[read_addr & 0x1fffff]);
|
|
|
|
pclog("voodoo_fb_readl : %08X %08X %i %i %08X %08X\n", addr, temp, x, y, read_addr, *(uint32_t *)(&voodoo.fb_mem[4]));
|
|
return temp;
|
|
}
|
|
static void voodoo_fb_writew(uint32_t addr, uint16_t val, void *priv)
|
|
{
|
|
pclog("voodoo_fb_writew : %08X %04X\n", addr, val);
|
|
*(uint16_t *)(&voodoo.fb_mem[addr & 0x1fffff]) = val;
|
|
}
|
|
static void voodoo_fb_writel(uint32_t addr, uint32_t val, void *priv)
|
|
{
|
|
int x, y;
|
|
uint32_t write_addr, write_addr_aux;
|
|
uint32_t colour_data, depth_data;
|
|
int write_mask, count = 1;
|
|
|
|
pclog("voodoo_fb_writel : %08X %08X\n", addr, val);
|
|
|
|
if (voodoo.lfbMode & 0x100)
|
|
fatal("voodoo_fb_writel : using pixel processing\n");
|
|
|
|
switch (voodoo.lfbMode & LFB_FORMAT_MASK)
|
|
{
|
|
case LFB_FORMAT_RGB565:
|
|
colour_data = val;
|
|
write_mask = LFB_WRITE_COLOUR;
|
|
break;
|
|
|
|
case LFB_FORMAT_DEPTH:
|
|
depth_data = val;
|
|
write_mask = LFB_WRITE_DEPTH;
|
|
addr <<= 1;
|
|
count = 2;
|
|
break;
|
|
|
|
default:
|
|
fatal("voodoo_fb_writel : bad LFB format %08X\n", voodoo.lfbMode);
|
|
}
|
|
|
|
x = addr & 0x3fe;
|
|
y = (addr >> 10) & 0x3ff;
|
|
|
|
write_addr = voodoo.fb_read_offset + x + (y * voodoo.row_width);
|
|
write_addr_aux = voodoo.aux_offset + x + (y * voodoo.row_width);
|
|
|
|
while (count--)
|
|
{
|
|
if (write_mask & LFB_WRITE_COLOUR)
|
|
*(uint16_t *)(&voodoo.fb_mem[write_addr & 0x1ffffe]) = colour_data;
|
|
if (write_mask & LFB_WRITE_DEPTH)
|
|
*(uint16_t *)(&voodoo.fb_mem[write_addr_aux & 0x1ffffe]) = depth_data;
|
|
|
|
colour_data >>= 16;
|
|
depth_data >>= 16;
|
|
|
|
write_addr += 2;
|
|
write_addr_aux += 2;
|
|
}
|
|
}
|
|
|
|
static void voodoo_tex_writew(uint32_t addr, uint16_t val, void *priv)
|
|
{
|
|
pclog("voodoo_tex_write : %08X %04X\n", addr, val);
|
|
*(uint16_t *)(&voodoo.tex_mem[addr & 0x1fffff]) = val;
|
|
}
|
|
static void voodoo_tex_writel(uint32_t addr, uint32_t val, void *priv)
|
|
{
|
|
pclog("voodoo_tex_write : %08X %08X\n", addr, val);
|
|
*(uint32_t *)(&voodoo.tex_mem[addr & 0x1fffff]) = val;
|
|
}
|
|
|
|
static void voodoo_recalcmapping()
|
|
{
|
|
if (voodoo.pci_enable)
|
|
{
|
|
pclog("voodoo_recalcmapping : memBaseAddr %08X\n", voodoo.memBaseAddr);
|
|
mem_mapping_set_addr(&voodoo.mmio_mapping, voodoo.memBaseAddr, 0x00400000);
|
|
mem_mapping_set_addr(&voodoo.fb_mapping, voodoo.memBaseAddr + 0x00400000, 0x00400000);
|
|
mem_mapping_set_addr(&voodoo.tex_mapping, voodoo.memBaseAddr + 0x00800000, 0x00800000);
|
|
}
|
|
else
|
|
{
|
|
pclog("voodoo_recalcmapping : disabled\n");
|
|
mem_mapping_disable(&voodoo.mmio_mapping);
|
|
mem_mapping_disable(&voodoo.fb_mapping);
|
|
mem_mapping_disable(&voodoo.tex_mapping);
|
|
}
|
|
}
|
|
|
|
uint8_t voodoo_pci_read(int func, int addr, void *priv)
|
|
{
|
|
pclog("Voodoo PCI read %08X\n", addr);
|
|
switch (addr)
|
|
{
|
|
case 0x00: return 0x1a; /*3dfx*/
|
|
case 0x01: return 0x12;
|
|
|
|
case 0x02: return 0x01; /*SST-1 (Voodoo Graphics)*/
|
|
case 0x03: return 0x00;
|
|
|
|
case 0x04: return voodoo.pci_enable ? 0x02 : 0x00; /*Respond to memory accesses*/
|
|
|
|
case 0x08: return 0; /*Revision ID*/
|
|
case 0x09: return 0; /*Programming interface*/
|
|
|
|
case 0x10: return 0x00; /*memBaseAddr*/
|
|
case 0x11: return 0x00;
|
|
case 0x12: return 0x00;
|
|
case 0x13: return voodoo.memBaseAddr >> 24;
|
|
|
|
case 0x40: return voodoo.initEnable;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void voodoo_pci_write(int func, int addr, uint8_t val, void *priv)
|
|
{
|
|
pclog("Voodoo PCI write %04X %02X\n", addr, val);
|
|
switch (addr)
|
|
{
|
|
case 0x04: voodoo.pci_enable = val & 2; voodoo_recalcmapping(); break;
|
|
|
|
case 0x13: voodoo.memBaseAddr = val << 24; voodoo_recalcmapping(); break;
|
|
|
|
case 0x40: voodoo.initEnable = val; break;
|
|
}
|
|
}
|
|
|
|
void voodoo_init()
|
|
{
|
|
return;
|
|
voodoo_make_dither();
|
|
pci_add(voodoo_pci_read, voodoo_pci_write, NULL);
|
|
|
|
mem_mapping_add(&voodoo.mmio_mapping, 0, 0, NULL, NULL, voodoo_readl, NULL, NULL, voodoo_writel, NULL);
|
|
mem_mapping_add(&voodoo.fb_mapping, 0, 0, NULL, voodoo_fb_readw, voodoo_fb_readl, NULL, voodoo_fb_writew, voodoo_fb_writel, NULL);
|
|
mem_mapping_add(&voodoo.tex_mapping, 0, 0, NULL, NULL, NULL, NULL, voodoo_tex_writew, voodoo_tex_writel, NULL);
|
|
|
|
voodoo.fb_mem = malloc(2 * 1024 * 1024);
|
|
voodoo.tex_mem = malloc(2 * 1024 * 1024);
|
|
}
|