PCem Permedia 2 emulation

Support and general discussion.
Post Reply
Bogus
Posts: 22
Joined: Tue 31 Jan, 2017 2:16 pm

PCem Permedia 2 emulation

Post by Bogus »

I trying to write Permedia 2 emulation, but i not know which registers are to read bank and write bank, in documentation is nothing about this registers, only about VGAControlReg and Mode640Reg, sequencer and graphics index register.
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
};
User avatar
omarsis81
Posts: 945
Joined: Thu 17 Dec, 2015 6:20 pm

Re: PCem Permedia 2 emulation

Post by omarsis81 »

I have no idea about what you ask, but I wish you all the luck with that noble task
Bogus
Posts: 22
Joined: Tue 31 Jan, 2017 2:16 pm

Re: PCem Permedia 2 emulation

Post by Bogus »

This is about bank registers, permedia 2 supports only 256 colors in 640x400 and in 640x480 resolutions, rest resolutions and colors depth works only in linear framebuffer.
Maybe SarahWalker will know, has register documentation.
vbdasc
Posts: 37
Joined: Tue 21 Mar, 2017 10:53 am

Re: PCem Permedia 2 emulation

Post by vbdasc »

Bogus wrote: Thu 27 Aug, 2020 7:56 pm This is about bank registers, permedia 2 supports only 256 colors in 640x400 and in 640x480 resolutions, rest resolutions and colors depth works only in linear framebuffer.
Maybe SarahWalker will know, has register documentation.
She said in another thread that she had the necessary info about the registers, so I'm bumping this thread to make it easier for her to notice it :)
Bogus
Posts: 22
Joined: Tue 31 Jan, 2017 2:16 pm

Re: PCem Permedia 2 emulation

Post by Bogus »

I know, i readed about this, only i not know, how banking registers works on this card, maybe like on mystique?
A0000 to B0000 and B0000 to C0000, additional address bits.
Post Reply