From 6df66c59fbdd1d01fc33acf6571226f16b50dcf2 Mon Sep 17 00:00:00 2001 From: SarahW Date: Thu, 8 Oct 2020 17:56:28 +0100 Subject: [PATCH] Add Voodoo 3 emulation. --- src/ibm.h | 2 + src/vid_voodoo.c | 4 +- src/vid_voodoo_banshee.c | 91 +++++++++++++++++++++++++++++++++++----- src/vid_voodoo_banshee.h | 2 + src/vid_voodoo_common.h | 3 +- src/vid_voodoo_fb.c | 8 ++-- src/vid_voodoo_fifo.c | 17 +++++--- src/vid_voodoo_reg.c | 30 ++++++------- src/vid_voodoo_texture.c | 11 +++-- src/video.c | 2 + 10 files changed, 128 insertions(+), 42 deletions(-) diff --git a/src/ibm.h b/src/ibm.h index 5365a29..90f24cb 100644 --- a/src/ibm.h +++ b/src/ibm.h @@ -323,6 +323,8 @@ enum GFX_TVGA9000B, /*Trident TVGA9000B*/ GFX_BANSHEE, /*Voodoo Banshee - reference PCI board with SGRAM*/ GFX_CL_BANSHEE, /*Creative Labs Voodoo Blaster Banshee PCI - with SDRAM*/ + GFX_VOODOO_3_2000, /*Voodoo 3 2000*/ + GFX_VOODOO_3_3000, /*Voodoo 3 3000*/ GFX_MAX }; diff --git a/src/vid_voodoo.c b/src/vid_voodoo.c index 414948f..6245106 100644 --- a/src/vid_voodoo.c +++ b/src/vid_voodoo.c @@ -1095,7 +1095,7 @@ void *voodoo_2d3d_card_init(int type) voodoo->use_recompiler = device_get_config_int("recompiler"); #endif voodoo->type = type; - voodoo->dual_tmus = 0; + voodoo->dual_tmus = (type == VOODOO_3) ? 1 : 0; /*generate filter lookup tables*/ voodoo_generate_filter_v2(voodoo); @@ -1304,7 +1304,7 @@ void voodoo_card_close(voodoo_t *voodoo) #ifndef NO_CODEGEN voodoo_codegen_close(voodoo); #endif - if (voodoo->type != VOODOO_BANSHEE && voodoo->fb_mem) + if (voodoo->type < VOODOO_BANSHEE && voodoo->fb_mem) { free(voodoo->fb_mem); if (voodoo->dual_tmus) diff --git a/src/vid_voodoo_banshee.c b/src/vid_voodoo_banshee.c index a65202c..816ce60 100644 --- a/src/vid_voodoo_banshee.c +++ b/src/vid_voodoo_banshee.c @@ -20,6 +20,13 @@ #undef CLAMP #endif +enum +{ + TYPE_BANSHEE = 0, + TYPE_V3_2000, + TYPE_V3_3000 +}; + typedef struct banshee_t { svga_t svga; @@ -70,6 +77,8 @@ typedef struct banshee_t uint32_t desktop_addr; int desktop_y; uint32_t desktop_stride_tiled; + + int type; } banshee_t; enum @@ -734,6 +743,9 @@ static uint32_t banshee_ext_inl(uint16_t addr, void *p) case Init_status: ret = banshee_status(banshee); // pclog("Read status reg! %04x(%08x):%08x\n", CS, cs, cpu_state.pc); + break; + case Init_pciInit0: + ret = banshee->pciInit0; break; case Init_lfbMemoryConfig: ret = banshee->lfbMemoryConfig; @@ -1818,13 +1830,15 @@ static uint8_t banshee_pci_read(int func, int addr, void *p) // svga_t *svga = &banshee->svga; uint8_t ret = 0; + if (func) + return 0xff; pclog("Banshee PCI read %08X ", addr); switch (addr) { case 0x00: ret = 0x1a; break; /*3DFX*/ case 0x01: ret = 0x12; break; - case 0x02: ret = 0x03; break; + case 0x02: ret = (banshee->type == TYPE_BANSHEE) ? 0x03 : 0x05; break; case 0x03: ret = 0x00; break; case 0x04: ret = banshee->pci_regs[0x04] & 0x27; break; @@ -1854,6 +1868,12 @@ static uint8_t banshee_pci_read(int func, int addr, void *p) case 0x1a: ret = 0x00; break; case 0x1b: ret = 0x00; break; + /*Undocumented, but Voodoo 3 BIOS checks this*/ + case 0x2c: ret = 0x1a; break; + case 0x2d: ret = 0x12; break; + case 0x2e: ret = (banshee->type == TYPE_V3_3000) ? 0x3a : 0x30; break; + case 0x2f: ret = 0x00; break; + case 0x30: ret = banshee->pci_regs[0x30] & 0x01; break; /*BIOS ROM address*/ case 0x31: ret = 0x00; break; case 0x32: ret = banshee->pci_regs[0x32]; break; @@ -1880,6 +1900,8 @@ static void banshee_pci_write(int func, int addr, uint8_t val, void *p) banshee_t *banshee = (banshee_t *)p; // svga_t *svga = &banshee->svga; + if (func) + return; pclog("Banshee write %08X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); switch (addr) { @@ -1941,7 +1963,7 @@ static void banshee_pci_write(int func, int addr, uint8_t val, void *p) { uint32_t addr = (banshee->pci_regs[0x32] << 16) | (banshee->pci_regs[0x33] << 24); pclog("Banshee bios_rom enabled at %08x\n", addr); - mem_mapping_set_addr(&banshee->bios_rom.mapping, addr, 0x8000); + mem_mapping_set_addr(&banshee->bios_rom.mapping, addr, 0x10000); mem_mapping_enable(&banshee->bios_rom.mapping); } else @@ -2066,14 +2088,17 @@ static device_config_t banshee_sdram_config[] = } }; -static void *banshee_init_common(char *fn, int has_sgram) +static void *banshee_init_common(char *fn, int has_sgram, int type, int voodoo_type) { int mem_size; banshee_t *banshee = malloc(sizeof(banshee_t)); memset(banshee, 0, sizeof(banshee_t)); - - rom_init(&banshee->bios_rom, fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + banshee->type = type; + + rom_init(&banshee->bios_rom, fn, 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); + mem_mapping_disable(&banshee->bios_rom.mapping); + if (has_sgram) mem_size = device_get_config_int("memory"); else @@ -2125,10 +2150,10 @@ static void *banshee_init_common(char *fn, int has_sgram) if (!has_sgram) banshee->dramInit1 = 1 << 30; /*SDRAM*/ banshee->svga.decode_mask = 0x1ffffff; - + pci_add(banshee_pci_read, banshee_pci_write, banshee); - banshee->voodoo = voodoo_2d3d_card_init(VOODOO_BANSHEE); + banshee->voodoo = voodoo_2d3d_card_init(voodoo_type); banshee->voodoo->p = banshee; banshee->voodoo->vram = banshee->svga.vram; banshee->voodoo->changedvram = banshee->svga.changedvram; @@ -2136,18 +2161,28 @@ static void *banshee_init_common(char *fn, int has_sgram) banshee->voodoo->fb_mask = banshee->svga.vram_mask; banshee->voodoo->tex_mem[0] = banshee->svga.vram; banshee->voodoo->tex_mem_w[0] = (uint16_t *)banshee->svga.vram; + banshee->voodoo->tex_mem[1] = banshee->svga.vram; + banshee->voodoo->tex_mem_w[1] = (uint16_t *)banshee->svga.vram; banshee->voodoo->texture_mask = banshee->svga.vram_mask; return banshee; } -static void *banshee_init(FILE *f, int has_sgram) +static void *banshee_init() { - return banshee_init_common("pci_sg.rom", 1); + return banshee_init_common("pci_sg.rom", 1, TYPE_BANSHEE, VOODOO_BANSHEE); } -static void *creative_banshee_init(FILE *f, int has_sgram) +static void *creative_banshee_init() { - return banshee_init_common("blasterpci.rom", 0); + return banshee_init_common("blasterpci.rom", 0, TYPE_BANSHEE, VOODOO_BANSHEE); +} +static void *v3_2000_init() +{ + return banshee_init_common("voodoo3_2000/2k11sd.rom", 0, TYPE_V3_2000, VOODOO_3); +} +static void *v3_3000_init() +{ + return banshee_init_common("voodoo3_3000/3k12sd.rom", 0, TYPE_V3_3000, VOODOO_3); } static int banshee_available() @@ -2158,6 +2193,14 @@ static int creative_banshee_available() { return rom_present("blasterpci.rom"); } +static int v3_2000_available() +{ + return rom_present("voodoo3_2000/2k11sd.rom"); +} +static int v3_3000_available() +{ + return rom_present("voodoo3_3000/3k12sd.rom"); +} static void banshee_close(void *p) { @@ -2281,3 +2324,29 @@ device_t creative_voodoo_banshee_device = banshee_add_status_info, banshee_sdram_config }; + +device_t voodoo_3_2000_device = +{ + "Voodoo 3 2000 PCI", + 0, + v3_2000_init, + banshee_close, + v3_2000_available, + banshee_speed_changed, + banshee_force_redraw, + banshee_add_status_info, + banshee_sdram_config +}; + +device_t voodoo_3_3000_device = +{ + "Voodoo 3 3000 PCI", + 0, + v3_3000_init, + banshee_close, + v3_3000_available, + banshee_speed_changed, + banshee_force_redraw, + banshee_add_status_info, + banshee_sdram_config +}; diff --git a/src/vid_voodoo_banshee.h b/src/vid_voodoo_banshee.h index 6e72747..ddd7e3f 100644 --- a/src/vid_voodoo_banshee.h +++ b/src/vid_voodoo_banshee.h @@ -1,4 +1,6 @@ extern device_t voodoo_banshee_device; extern device_t creative_voodoo_banshee_device; +extern device_t voodoo_3_2000_device; +extern device_t voodoo_3_3000_device; void banshee_set_overlay_addr(void *p, uint32_t addr); diff --git a/src/vid_voodoo_common.h b/src/vid_voodoo_common.h index 2bab154..c72d079 100644 --- a/src/vid_voodoo_common.h +++ b/src/vid_voodoo_common.h @@ -22,7 +22,8 @@ enum VOODOO_1 = 0, VOODOO_SB50, VOODOO_2, - VOODOO_BANSHEE + VOODOO_BANSHEE, + VOODOO_3 }; typedef union int_float diff --git a/src/vid_voodoo_fb.c b/src/vid_voodoo_fb.c index 52bec1f..b3d3918 100644 --- a/src/vid_voodoo_fb.c +++ b/src/vid_voodoo_fb.c @@ -18,7 +18,7 @@ uint16_t voodoo_fb_readw(uint32_t addr, void *p) uint32_t read_addr; uint16_t temp; - if (voodoo->type == VOODOO_BANSHEE) + if (voodoo->type >= VOODOO_BANSHEE) { x = addr & 0xffe; y = (addr >> 12) & 0x3ff; @@ -61,7 +61,7 @@ uint32_t voodoo_fb_readl(uint32_t addr, void *p) uint32_t read_addr; uint32_t temp; - if (voodoo->type == VOODOO_BANSHEE) + if (voodoo->type >= VOODOO_BANSHEE) { x = addr & 0xffe; y = (addr >> 12) & 0x3ff; @@ -175,7 +175,7 @@ void voodoo_fb_writew(uint32_t addr, uint16_t val, void *p) fatal("voodoo_fb_writew : bad LFB format %08X\n", voodoo->lfbMode); } - if (voodoo->type == VOODOO_BANSHEE) + if (voodoo->type >= VOODOO_BANSHEE) { x = addr & 0xffe; y = (addr >> 12) & 0x3ff; @@ -336,7 +336,7 @@ void voodoo_fb_writel(uint32_t addr, uint32_t val, void *p) fatal("voodoo_fb_writel : bad LFB format %08X\n", voodoo->lfbMode); } - if (voodoo->type == VOODOO_BANSHEE) + if (voodoo->type >= VOODOO_BANSHEE) { x = addr & 0xffe; y = (addr >> 12) & 0x3ff; diff --git a/src/vid_voodoo_fifo.c b/src/vid_voodoo_fifo.c index c5ca5a9..35f63bf 100644 --- a/src/vid_voodoo_fifo.c +++ b/src/vid_voodoo_fifo.c @@ -277,7 +277,7 @@ void voodoo_fifo_thread(void *param) while (num--) { uint32_t val = cmdfifo_get(voodoo); - if ((addr & (1 << 13)) && voodoo->type == VOODOO_BANSHEE) + if ((addr & (1 << 13)) && voodoo->type >= VOODOO_BANSHEE) { // if (voodoo->type != VOODOO_BANSHEE) // fatal("CMDFIFO1: Not Banshee\n"); @@ -290,7 +290,7 @@ void voodoo_fifo_thread(void *param) (addr & 0x3ff) == SST_fastfillCMD || (addr & 0x3ff) == SST_nopCMD) voodoo->cmd_written_fifo++; - if (voodoo->type == VOODOO_BANSHEE && (addr & 0x3ff) == SST_swapbufferCMD) + if (voodoo->type >= VOODOO_BANSHEE && (addr & 0x3ff) == SST_swapbufferCMD) voodoo->cmd_written_fifo++; voodoo_reg_writel(addr, val, voodoo); } @@ -301,7 +301,7 @@ void voodoo_fifo_thread(void *param) break; case 2: - if (voodoo->type != VOODOO_BANSHEE) + if (voodoo->type < VOODOO_BANSHEE) fatal("CMDFIFO2: Not Banshee\n"); mask = (header >> 3); addr = 8; @@ -393,9 +393,9 @@ void voodoo_fifo_thread(void *param) { uint32_t val = cmdfifo_get(voodoo); - if ((addr & (1 << 13)) && voodoo->type == VOODOO_BANSHEE) + if ((addr & (1 << 13)) && voodoo->type >= VOODOO_BANSHEE) { - if (voodoo->type != VOODOO_BANSHEE) + if (voodoo->type < VOODOO_BANSHEE) fatal("CMDFIFO1: Not Banshee\n"); // pclog("CMDFIFO1: write %08x %08x\n", addr, val); voodoo_2d_reg_writel(voodoo, addr, val); @@ -406,7 +406,7 @@ void voodoo_fifo_thread(void *param) (addr & 0x3ff) == SST_fastfillCMD || (addr & 0x3ff) == SST_nopCMD) voodoo->cmd_written_fifo++; - if (voodoo->type == VOODOO_BANSHEE && (addr & 0x3ff) == SST_swapbufferCMD) + if (voodoo->type >= VOODOO_BANSHEE && (addr & 0x3ff) == SST_swapbufferCMD) voodoo->cmd_written_fifo++; voodoo_reg_writel(addr, val, voodoo); } @@ -435,6 +435,11 @@ void voodoo_fifo_thread(void *param) // pclog("texture_present at %08x %i\n", addr, (addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT); flush_texture_cache(voodoo, addr & voodoo->texture_mask, 0); } + if (voodoo->texture_present[1][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT]) + { +// pclog("texture_present at %08x %i\n", addr, (addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT); + flush_texture_cache(voodoo, addr & voodoo->texture_mask, 1); + } while (num--) { uint32_t val = cmdfifo_get(voodoo); diff --git a/src/vid_voodoo_reg.c b/src/vid_voodoo_reg.c index 1af1131..965c6f6 100644 --- a/src/vid_voodoo_reg.c +++ b/src/vid_voodoo_reg.c @@ -48,7 +48,7 @@ void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) switch (addr) { case SST_swapbufferCMD: - if (voodoo->type == VOODOO_BANSHEE) + if (voodoo->type >= VOODOO_BANSHEE) { // pclog("swapbufferCMD %08x %08x\n", val, voodoo->leftOverlayBuf); @@ -537,14 +537,14 @@ void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) break; case SST_clipLeftRight1: - if (voodoo->type == VOODOO_BANSHEE) + if (voodoo->type >= VOODOO_BANSHEE) { voodoo->params.clipRight1 = val & 0xfff; voodoo->params.clipLeft1 = (val >> 16) & 0xfff; } break; case SST_clipTopBottom1: - if (voodoo->type == VOODOO_BANSHEE) + if (voodoo->type >= VOODOO_BANSHEE) { voodoo->params.clipHighY1 = val & 0xfff; voodoo->params.clipLowY1 = (val >> 16) & 0xfff; @@ -552,7 +552,7 @@ void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) break; case SST_colBufferAddr: - if (voodoo->type == VOODOO_BANSHEE) + if (voodoo->type >= VOODOO_BANSHEE) { voodoo->params.draw_offset = val & 0xfffff0; voodoo->fb_write_offset = voodoo->params.draw_offset; @@ -560,7 +560,7 @@ void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) } break; case SST_colBufferStride: - if (voodoo->type == VOODOO_BANSHEE) + if (voodoo->type >= VOODOO_BANSHEE) { voodoo->col_tiled = val & (1 << 15); if (voodoo->col_tiled) @@ -576,14 +576,14 @@ void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) } break; case SST_auxBufferAddr: - if (voodoo->type == VOODOO_BANSHEE) + if (voodoo->type >= VOODOO_BANSHEE) { voodoo->params.aux_offset = val & 0xfffff0; // pclog("auxBufferAddr=%06x\n", voodoo->params.aux_offset); } break; case SST_auxBufferStride: - if (voodoo->type == VOODOO_BANSHEE) + if (voodoo->type >= VOODOO_BANSHEE) { voodoo->aux_tiled = val & (1 << 15); if (voodoo->aux_tiled) @@ -877,7 +877,7 @@ void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) case SST_texBaseAddr: if (chip & CHIP_TREX0) { - if (voodoo->type == VOODOO_BANSHEE) + if (voodoo->type >= VOODOO_BANSHEE) voodoo->params.texBaseAddr[0] = val & 0xfffff0; else voodoo->params.texBaseAddr[0] = (val & 0x7ffff) << 3; @@ -886,7 +886,7 @@ void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) } if (chip & CHIP_TREX1) { - if (voodoo->type == VOODOO_BANSHEE) + if (voodoo->type >= VOODOO_BANSHEE) voodoo->params.texBaseAddr[1] = val & 0xfffff0; else voodoo->params.texBaseAddr[1] = (val & 0x7ffff) << 3; @@ -896,7 +896,7 @@ void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) case SST_texBaseAddr1: if (chip & CHIP_TREX0) { - if (voodoo->type == VOODOO_BANSHEE) + if (voodoo->type >= VOODOO_BANSHEE) voodoo->params.texBaseAddr1[0] = val & 0xfffff0; else voodoo->params.texBaseAddr1[0] = (val & 0x7ffff) << 3; @@ -904,7 +904,7 @@ void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) } if (chip & CHIP_TREX1) { - if (voodoo->type == VOODOO_BANSHEE) + if (voodoo->type >= VOODOO_BANSHEE) voodoo->params.texBaseAddr1[1] = val & 0xfffff0; else voodoo->params.texBaseAddr1[1] = (val & 0x7ffff) << 3; @@ -914,7 +914,7 @@ void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) case SST_texBaseAddr2: if (chip & CHIP_TREX0) { - if (voodoo->type == VOODOO_BANSHEE) + if (voodoo->type >= VOODOO_BANSHEE) voodoo->params.texBaseAddr2[0] = val & 0xfffff0; else voodoo->params.texBaseAddr2[0] = (val & 0x7ffff) << 3; @@ -922,7 +922,7 @@ void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) } if (chip & CHIP_TREX1) { - if (voodoo->type == VOODOO_BANSHEE) + if (voodoo->type >= VOODOO_BANSHEE) voodoo->params.texBaseAddr2[1] = val & 0xfffff0; else voodoo->params.texBaseAddr2[1] = (val & 0x7ffff) << 3; @@ -932,7 +932,7 @@ void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) case SST_texBaseAddr38: if (chip & CHIP_TREX0) { - if (voodoo->type == VOODOO_BANSHEE) + if (voodoo->type >= VOODOO_BANSHEE) voodoo->params.texBaseAddr38[0] = val & 0xfffff0; else voodoo->params.texBaseAddr38[0] = (val & 0x7ffff) << 3; @@ -940,7 +940,7 @@ void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) } if (chip & CHIP_TREX1) { - if (voodoo->type == VOODOO_BANSHEE) + if (voodoo->type >= VOODOO_BANSHEE) voodoo->params.texBaseAddr38[1] = val & 0xfffff0; else voodoo->params.texBaseAddr38[1] = (val & 0x7ffff) << 3; diff --git a/src/vid_voodoo_texture.c b/src/vid_voodoo_texture.c index 0396a8a..f52a314 100644 --- a/src/vid_voodoo_texture.c +++ b/src/vid_voodoo_texture.c @@ -531,9 +531,9 @@ void voodoo_tex_writel(uint32_t addr, uint32_t val, void *p) if (tmu && !voodoo->dual_tmus) return; - if (voodoo->type != VOODOO_BANSHEE) + if (voodoo->type < VOODOO_BANSHEE) { - if (!(voodoo->params.tformat[tmu] & 8) && voodoo->type == VOODOO_BANSHEE) + if (!(voodoo->params.tformat[tmu] & 8) && voodoo->type >= VOODOO_BANSHEE) { lod = (addr >> 16) & 0xf; t = (addr >> 8) & 0xff; @@ -547,7 +547,7 @@ void voodoo_tex_writel(uint32_t addr, uint32_t val, void *p) s = (addr >> 1) & 0xfe; else { - if ((voodoo->params.textureMode[tmu] & (1 << 31)) || voodoo->type == VOODOO_BANSHEE) + if ((voodoo->params.textureMode[tmu] & (1 << 31)) || voodoo->type >= VOODOO_BANSHEE) s = addr & 0xfc; else s = (addr >> 1) & 0xfc; @@ -571,5 +571,10 @@ void voodoo_tex_writel(uint32_t addr, uint32_t val, void *p) // pclog("texture_present at %08x %i\n", addr, (addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT); flush_texture_cache(voodoo, addr & voodoo->texture_mask, tmu); } + if (voodoo->type == VOODOO_3 && voodoo->texture_present[tmu^1][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT]) + { +// pclog("texture_present at %08x %i\n", addr, (addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT); + flush_texture_cache(voodoo, addr & voodoo->texture_mask, tmu^1); + } *(uint32_t *)(&voodoo->tex_mem[tmu][addr & voodoo->texture_mask]) = val; } diff --git a/src/video.c b/src/video.c index a8c7dbb..b58bc1d 100644 --- a/src/video.c +++ b/src/video.c @@ -83,6 +83,8 @@ typedef struct static VIDEO_CARD video_cards[] = { + {"3DFX Voodoo 3 2000", "v3_2000", &voodoo_3_2000_device, GFX_VOODOO_3_2000, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}}, + {"3DFX Voodoo 3 3000", "v3_3000", &voodoo_3_3000_device, GFX_VOODOO_3_3000, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}}, {"Acumos AVGA2 / Cirrus Logic CL-GD5402", "avga2", &avga2_device, GFX_AVGA2, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, {"ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx", &mach64gx_device, GFX_MACH64GX, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}}, {"ATI Video Xpression (Mach64 VT2)", "mach64vt2", &mach64vt2_device, GFX_MACH64VT2, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}},