#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);        
}
