What works?
pci vendor device id
pci subsystem vendor id, pci subsystem id
pci interrupt
vga
what not works?
banked vesa framebuffer
linear vesa framebuffer
everything else
my current vid_permedia2.c code:
Code: Select all
/*3Dlabs Permedia 2 emulation*/
#include <stdlib.h>
#include "ibm.h"
#include "device.h"
#include "io.h"
#include "mem.h"
#include "pci.h"
#include "rom.h"
#include "video.h"
#include "vid_permedia2.h"
#include "vid_svga.h"
#include "vid_svga_render.h"
typedef struct permedia2_t
{
mem_mapping_t linear_mapping;
rom_t bios_rom;
svga_t svga;
uint8_t pci_regs[256];
int memory_size;
} permedia2_t;
static uint8_t permedia2_in(uint16_t addr, void *p)
{
permedia2_t *permedia2 = (permedia2_t *)p;
svga_t *svga = &permedia2->svga;
uint8_t ret;
if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1))
addr ^= 0x60;
// if (addr != 0x3da) pclog("Permedia 2 in %04X %04X:%08X ", addr, CS, cpu_state.pc);
switch (addr)
{
case 0x3D4:
ret = svga->crtcreg;
break;
case 0x3D5:
ret = svga->crtc[svga->crtcreg];
break;
default:
ret = svga_in(addr, svga);
break;
}
// if (addr != 0x3da) pclog("%02X\n", ret);
return ret;
}
static void permedia2_out(uint16_t addr, uint8_t val, void *p)
{
permedia2_t *permedia2 = (permedia2_t *)p;
svga_t *svga = &permedia2->svga;
uint8_t old;
if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1))
addr ^= 0x60;
pclog("Permedia 2 out %04X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc);
switch (addr)
{
case 0x3D4:
svga->crtcreg = val;
return;
case 0x3D5:
//pclog("Write CRTC R%02X %02X %04x(%08x):%08x\n", svga->crtcreg, val, CS, cs, cpu_state.pc);
if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80))
return;
if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80))
val = (svga->crtc[7] & ~0x10) | (val & 0x10);
old = svga->crtc[svga->crtcreg];
svga->crtc[svga->crtcreg] = val;
if (old != val)
{
if (svga->crtcreg < 0xe || svga->crtcreg > 0x10)
{
svga->fullchange = changeframecount;
svga_recalctimings(svga);
}
}
break;
}
svga_out(addr, val, svga);
}
static void permedia2_recalctimings(svga_t *svga)
{
}
static uint8_t permedia2_pci_read(int func, int addr, void *p)
{
permedia2_t *permedia2 = (permedia2_t *)p;
svga_t *svga = &permedia2->svga;
uint8_t ret = 0;
// pclog("Permedia 2 PCI read %08X \n", addr);
switch (addr)
{
case 0x00: ret = 0x4c; break; /*'Texas Instruments'*/
case 0x01: ret = 0x10; break;
case 0x02: ret = 0x07; break; /*'Permedia 2'*/
case 0x03: ret = 0x3d; break;
case 0x04: ret = permedia2->pci_regs[0x04] & 0x27; break;
case 0x08: ret = 0x01; break; /*Revision ID*/
case 0x09: ret = 0; break; /*Programming interface*/
case 0x0a: ret = 0x00; break; /*Supports VGA interface*/
case 0x0b: ret = 0x03; /*output = 3;*/ break;
case 0x0e: ret = 0x00; break; /*Header type*/
case 0x2c: ret = permedia2->pci_regs[0x2c]; break; /*Subsystem Vendor ID*/
case 0x2d: ret = permedia2->pci_regs[0x2d]; break;
case 0x2e: ret = permedia2->pci_regs[0x2e]; break; /*Subsystem ID*/
case 0x2f: ret = permedia2->pci_regs[0x2f]; break;
case 0x3c: ret = permedia2->pci_regs[0x3c]; break;
case 0x3d: ret = 0x01; break; /*INTA*/
}
// pclog("%02X\n", ret);
return ret;
}
static void permedia2_pci_write(int func, int addr, uint8_t val, void *p)
{
permedia2_t *permedia2 = (permedia2_t *)p;
svga_t *svga = &permedia2->svga;
// pclog("Permedia 2 PCI write %08X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc);
switch (addr)
{
case 0x2c: case 0x2d: case 0x2e: case 0x2f:
permedia2->pci_regs[addr - 0x20] = val;
break;
case 0x30: case 0x32: case 0x33:
permedia2->pci_regs[addr] = val;
if (permedia2->pci_regs[0x30] & 0x01)
{
uint32_t addr = (permedia2->pci_regs[0x32] << 16) | (permedia2->pci_regs[0x33] << 24);
//pclog("Permedia 2 bios_rom enabled at %08x\n", addr);
mem_mapping_set_addr(&permedia2->bios_rom.mapping, addr, 0x8000);
mem_mapping_enable(&permedia2->bios_rom.mapping);
}
else
{
//pclog("Permedia 2 bios_rom disabled\n");
mem_mapping_disable(&permedia2->bios_rom.mapping);
}
return;
case 0x3c:
permedia2->pci_regs[0x3c] = val;
return;
}
}
static void *permedia2_init()
{
permedia2_t *permedia2 = malloc(sizeof(permedia2_t));
memset(permedia2, 0, sizeof(permedia2_t));
permedia2->memory_size = device_get_config_int("memory");
svga_init(&permedia2->svga, permedia2, permedia2->memory_size << 20,
permedia2_recalctimings,
permedia2_in, permedia2_out,
NULL, NULL);
rom_init(&permedia2->bios_rom, "MS4413_ver.1_permedia2_27E257.BIN", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
if (PCI)
mem_mapping_disable(&permedia2->bios_rom.mapping);
mem_mapping_add(&permedia2->linear_mapping, 0, 0, svga_read_linear,
svga_readw_linear,
svga_readl_linear,
svga_write_linear,
svga_writew_linear,
svga_writel_linear,
NULL,
0,
&permedia2->svga);
io_sethandler(0x03c0, 0x0020, permedia2_in, NULL, NULL, permedia2_out, NULL, NULL, permedia2);
permedia2->pci_regs[4] = 3;
permedia2->pci_regs[5] = 0;
permedia2->pci_regs[6] = 0;
permedia2->pci_regs[7] = 2;
permedia2->pci_regs[0x2c] = permedia2->bios_rom.rom[0x7ffc];
permedia2->pci_regs[0x2d] = permedia2->bios_rom.rom[0x7ffd];
permedia2->pci_regs[0x2e] = permedia2->bios_rom.rom[0x7ffe];
permedia2->pci_regs[0x2f] = permedia2->bios_rom.rom[0x7fff];
pci_add(permedia2_pci_read, permedia2_pci_write, permedia2);
return permedia2;
}
static int permedia2_available()
{
return rom_present("MS4413_ver.1_permedia2_27E257.BIN");
}
static void permedia2_speed_changed(void *p)
{
permedia2_t *permedia2 = (permedia2_t *)p;
svga_recalctimings(&permedia2->svga);
}
static void permedia2_force_redraw(void *p)
{
permedia2_t *permedia2 = (permedia2_t *)p;
permedia2->svga.fullchange = changeframecount;
}
static void permedia2_add_status_info(char *s, int max_len, void *p)
{
permedia2_t *permedia2 = (permedia2_t *)p;
svga_add_status_info(s, max_len, &permedia2->svga);
}
static device_config_t permedia2_config[] =
{
{
.name = "memory",
.description = "Memory size",
.type = CONFIG_SELECTION,
.selection =
{
{
.description = "4 MB",
.value = 4
},
{
.description = ""
}
},
.default_int = 4
},
{
.type = -1
}
};
device_t permedia2_device =
{
"3Dlabs Permedia 2",
0,
permedia2_init,
NULL,
permedia2_available,
permedia2_speed_changed,
permedia2_force_redraw,
permedia2_add_status_info,
permedia2_config
};