Implement plug and play monitor support on Voodoo Banshee & 3.

This commit is contained in:
SarahW 2020-10-15 20:20:12 +01:00
commit 5eb6f4d168
7 changed files with 343 additions and 3 deletions

View file

@ -43,7 +43,7 @@ scsi_ibm.c scsi_zip.c serial.c sio.c sis496.c sl82c460.c sound.c sound_ad1848.c
sound_azt2316a.c sound_cms.c sound_emu8k.c sound_gus.c sound_mpu401_uart.c sound_opl.c sound_pas16.c sound_ps1.c sound_pssj.c \ sound_azt2316a.c sound_cms.c sound_emu8k.c sound_gus.c sound_mpu401_uart.c sound_opl.c sound_pas16.c sound_ps1.c sound_pssj.c \
sound_sb.c sound_sb_dsp.c sound_sn76489.c sound_speaker.c sound_ssi2001.c sound_wss.c sound_ym7128.c soundopenal.c \ sound_sb.c sound_sb_dsp.c sound_sn76489.c sound_speaker.c sound_ssi2001.c sound_wss.c sound_ym7128.c soundopenal.c \
sst39sf010.c tandy_eeprom.c tandy_rom.c t1000.c t3100e.c timer.c um8669f.c um8881f.c vid_ati_eeprom.c vid_ati_mach64.c \ sst39sf010.c tandy_eeprom.c tandy_rom.c t1000.c t3100e.c timer.c um8669f.c um8881f.c vid_ati_eeprom.c vid_ati_mach64.c \
vid_ati18800.c vid_ati28800.c vid_ati68860_ramdac.c vid_cga.c vid_cl5429.c vid_colorplus.c vid_compaq_cga.c vid_ega.c \ vid_ati18800.c vid_ati28800.c vid_ati68860_ramdac.c vid_cga.c vid_cl5429.c vid_colorplus.c vid_compaq_cga.c vid_ddc.c vid_ega.c \
vid_et4000.c vid_et4000w32.c vid_genius.c vid_hercules.c vid_ht216.c vid_icd2061.c vid_ics2595.c vid_im1024.c \ vid_et4000.c vid_et4000w32.c vid_genius.c vid_hercules.c vid_ht216.c vid_icd2061.c vid_ics2595.c vid_im1024.c \
vid_incolor.c vid_mda.c vid_mga.c vid_olivetti_m24.c vid_oti037.c vid_oti067.c vid_paradise.c vid_pc200.c vid_pc1512.c \ vid_incolor.c vid_mda.c vid_mga.c vid_olivetti_m24.c vid_oti037.c vid_oti067.c vid_paradise.c vid_pc200.c vid_pc1512.c \
vid_pc1640.c vid_pcjr.c vid_pgc.c vid_ps1_svga.c vid_s3.c vid_s3_virge.c vid_sdac_ramdac.c vid_sigma.c \ vid_pc1640.c vid_pcjr.c vid_pgc.c vid_ps1_svga.c vid_s3.c vid_s3_virge.c vid_sdac_ramdac.c vid_sigma.c \

View file

@ -31,7 +31,7 @@ OBJ = 386.o 386_common.o 386_dynarec.o 386_dynarec_ops.o 808x.o 82091aa.o acc203
sound_resid.o sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o \ sound_resid.o sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o \
sound_ym7128.o soundopenal.o sst39sf010.o t1000.o t3100e.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o \ sound_ym7128.o soundopenal.o sst39sf010.o t1000.o t3100e.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o \
vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o vid_ati28800.o vid_ati68860_ramdac.o vid_cga.o \ vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o vid_ati28800.o vid_ati68860_ramdac.o vid_cga.o \
vid_cl5429.o vid_colorplus.o vid_compaq_cga.o vid_ega.o vid_et4000.o vid_et4000w32.o \ vid_cl5429.o vid_colorplus.o vid_compaq_cga.o vid_ddc.o vid_ega.o vid_et4000.o vid_et4000w32.o \
vid_et4000w32i.o vid_genius.o vid_hercules.o vid_ht216.o vid_icd2061.o vid_ics2595.o vid_im1024.o vid_incolor.o vid_mda.o \ vid_et4000w32i.o vid_genius.o vid_hercules.o vid_ht216.o vid_icd2061.o vid_ics2595.o vid_im1024.o vid_incolor.o vid_mda.o \
vid_mga.o vid_olivetti_m24.o vid_oti037.c vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o vid_pc200.o \ vid_mga.o vid_olivetti_m24.o vid_oti037.c vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o vid_pc200.o \
vid_pcjr.o vid_pgc.o vid_ps1_svga.o vid_s3.o vid_s3_virge.o vid_sdac_ramdac.o vid_sigma.o vid_stg_ramdac.o vid_svga.o \ vid_pcjr.o vid_pgc.o vid_ps1_svga.o vid_s3.o vid_s3_virge.o vid_sdac_ramdac.o vid_sigma.o vid_stg_ramdac.o vid_svga.o \

View file

@ -31,7 +31,7 @@ OBJ = 386.o 386_common.o 386_dynarec.o 386_dynarec_ops.o 808x.o 82091aa.o acc203
sound_resid.o sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o \ sound_resid.o sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o \
sound_ym7128.o soundopenal.o sst39sf010.o t1000.o t3100e.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o \ sound_ym7128.o soundopenal.o sst39sf010.o t1000.o t3100e.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o \
vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o vid_ati28800.o vid_ati68860_ramdac.o vid_cga.o \ vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o vid_ati28800.o vid_ati68860_ramdac.o vid_cga.o \
vid_cl5429.o vid_colorplus.o vid_compaq_cga.o vid_ega.o vid_et4000.o vid_et4000w32.o \ vid_cl5429.o vid_colorplus.o vid_compaq_cga.o vid_ddc.o vid_ega.o vid_et4000.o vid_et4000w32.o \
vid_et4000w32i.o vid_genius.o vid_hercules.o vid_ht216.o vid_icd2061.o vid_ics2595.o vid_im1024.o vid_incolor.o vid_mda.o \ vid_et4000w32i.o vid_genius.o vid_hercules.o vid_ht216.o vid_icd2061.o vid_ics2595.o vid_im1024.o vid_incolor.o vid_mda.o \
vid_mga.o vid_olivetti_m24.o vid_oti037.c vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o vid_pc200.o \ vid_mga.o vid_olivetti_m24.o vid_oti037.c vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o vid_pc200.o \
vid_pcjr.o vid_pgc.o vid_ps1_svga.o vid_s3.o vid_s3_virge.o vid_sdac_ramdac.o vid_sigma.o vid_stg_ramdac.o vid_svga.o \ vid_pcjr.o vid_pgc.o vid_ps1_svga.o vid_s3.o vid_s3_virge.o vid_sdac_ramdac.o vid_sigma.o vid_stg_ramdac.o vid_svga.o \

301
src/vid_ddc.c Normal file
View file

@ -0,0 +1,301 @@
#include "ibm.h"
#include "vid_ddc.h"
#include "x86.h"
static uint8_t edid_data[128] =
{
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, /*Fixed header pattern*/
0x65, 0x40, /*Manufacturer "PCE" - apparently unassigned by UEFI*/
0x00, 0x00, /*Product code*/
0x12, 0x34, 0x56, 0x78, /*Serial number*/
0x01, 9, /*Manufacturer week and year*/
0x01, 0x03, /*EDID version (1.3)*/
0x08, /*Analogue input, separate sync*/
34, 0, /*Landscape, 4:3*/
0, /*Gamma*/
0x08, /*RGB colour*/
0x81, 0xf1, 0xa3, 0x57, 0x53, 0x9f, 0x27, 0x0a, 0x50, /*Chromaticity*/
0xff, 0xff, 0xff, /*Established timing bitmap*/
0x00, 0x00, /*Standard timing information*/
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
/*Detailed mode descriptions*/
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, /*No extensions*/
0x00
};
/*This should probably be split off into a separate I2C module*/
enum
{
TRANSMITTER_MONITOR = 1,
TRANSMITTER_HOST = -1
};
enum
{
I2C_IDLE = 0,
I2C_RECEIVE,
I2C_RECEIVE_WAIT,
I2C_TRANSMIT_START,
I2C_TRANSMIT,
I2C_ACKNOWLEDGE,
I2C_TRANSACKNOWLEDGE,
I2C_TRANSMIT_WAIT
};
enum
{
PROM_IDLE = 0,
PROM_RECEIVEADDR,
PROM_RECEIVEDATA,
PROM_SENDDATA,
PROM_INVALID
};
static struct
{
int clock, data;
int state;
int last_data;
int pos;
int transmit;
uint8_t byte;
} i2c;
static struct
{
int state;
int addr;
int rw;
} prom;
static void prom_stop(void)
{
// pclog("prom_stop()\n");
prom.state = PROM_IDLE;
i2c.transmit = TRANSMITTER_HOST;
}
static void prom_next_byte(void)
{
// pclog("prom_next_byte(%d)\n", prom.addr);
i2c.byte = edid_data[(prom.addr++) & 0x7F];
}
static void prom_write(uint8_t byte)
{
// pclog("prom_write: byte=%02x\n", byte);
switch (prom.state)
{
case PROM_IDLE:
if ((byte & 0xfe) != 0xa0)
{
// pclog("I2C address not PROM\n");
prom.state = PROM_INVALID;
break;
}
prom.rw = byte & 1;
if (prom.rw)
{
prom.state = PROM_SENDDATA;
i2c.transmit = TRANSMITTER_MONITOR;
i2c.byte = edid_data[(prom.addr++) & 0x7F];
// pclog("PROM - %02X from %02X\n",i2c.byte, prom.addr-1);
// pclog("Transmitter now PROM\n");
}
else
{
prom.state = PROM_RECEIVEADDR;
i2c.transmit = TRANSMITTER_HOST;
}
// pclog("PROM R/W=%i\n",promrw);
return;
case PROM_RECEIVEADDR:
// pclog("PROM addr=%02X\n",byte);
prom.addr = byte;
if (prom.rw)
prom.state = PROM_SENDDATA;
else
prom.state = PROM_RECEIVEDATA;
break;
case PROM_RECEIVEDATA:
// pclog("PROM write %02X %02X\n",promaddr,byte);
break;
case PROM_SENDDATA:
break;
}
}
void ddc_i2c_change(int new_clock, int new_data)
{
// pclog("I2C update clock %i->%i data %i->%i state %i\n",i2c.clock,new_clock,i2c.last_data,new_data,i2c.state);
switch (i2c.state)
{
case I2C_IDLE:
if (i2c.clock && new_clock)
{
if (i2c.last_data && !new_data) /*Start bit*/
{
// pclog("Start bit received\n");
i2c.state = I2C_RECEIVE;
i2c.pos = 0;
}
}
break;
case I2C_RECEIVE_WAIT:
if (!i2c.clock && new_clock)
i2c.state = I2C_RECEIVE;
case I2C_RECEIVE:
if (!i2c.clock && new_clock)
{
i2c.byte <<= 1;
if (new_data)
i2c.byte |= 1;
else
i2c.byte &= 0xFE;
i2c.pos++;
if (i2c.pos == 8)
{
prom_write(i2c.byte);
i2c.state = I2C_ACKNOWLEDGE;
}
}
else if (i2c.clock && new_clock && new_data && !i2c.last_data) /*Stop bit*/
{
// pclog("Stop bit received\n");
i2c.state = I2C_IDLE;
prom_stop();
}
else if (i2c.clock && new_clock && !new_data && i2c.last_data) /*Start bit*/
{
// pclog("Start bit received\n");
i2c.pos = 0;
prom.state = PROM_IDLE;
}
break;
case I2C_ACKNOWLEDGE:
if (!i2c.clock && new_clock)
{
// pclog("Acknowledging transfer\n");
new_data = 0;
i2c.pos = 0;
if (i2c.transmit == TRANSMITTER_HOST)
i2c.state = I2C_RECEIVE_WAIT;
else
i2c.state = I2C_TRANSMIT;
}
break;
case I2C_TRANSACKNOWLEDGE:
if (!i2c.clock && new_clock)
{
if (new_data) /*It's not acknowledged - must be end of transfer*/
{
// pclog("End of transfer\n");
i2c.state = I2C_IDLE;
prom_stop();
}
else /*Next byte to transfer*/
{
i2c.state = I2C_TRANSMIT_START;
prom_next_byte();
i2c.pos = 0;
// pclog("Next byte - %02X\n",i2c.byte);
}
}
break;
case I2C_TRANSMIT_WAIT:
if (i2c.clock && new_clock)
{
if (i2c.last_data && !new_data) /*Start bit*/
{
prom_next_byte();
i2c.pos = 0;
// pclog("Next byte - %02X\n",i2c.byte);
}
if (!i2c.last_data && new_data) /*Stop bit*/
{
// pclog("Stop bit received\n");
i2c.state = I2C_IDLE;
prom_stop();
}
}
break;
case I2C_TRANSMIT_START:
if (!i2c.clock && new_clock)
i2c.state = I2C_TRANSMIT;
case I2C_TRANSMIT:
if (!i2c.clock && new_clock)
{
i2c.clock = new_clock;
// if (!i2c.pos)
// pclog("Transmit byte %02x\n", i2c.byte);
i2c.data = new_data = i2c.byte & 0x80;
// pclog("Transmit bit %i %i\n", i2c.byte, i2c.pos);
i2c.byte <<= 1;
i2c.pos++;
return;
}
if (i2c.clock && !new_clock && i2c.pos == 8)
{
i2c.state = I2C_TRANSACKNOWLEDGE;
// pclog("Acknowledge mode\n");
}
break;
}
if (!i2c.clock && new_clock)
i2c.data = new_data;
i2c.last_data = new_data;
i2c.clock = new_clock;
}
int ddc_read_clock(void)
{
return i2c.clock;
}
int ddc_read_data(void)
{
if (i2c.state == I2C_TRANSMIT || i2c.state == I2C_ACKNOWLEDGE)
return i2c.data;
if (i2c.state == I2C_RECEIVE_WAIT)
return 0; /*ACK*/
return 1;
}
void ddc_init(void)
{
int c;
uint8_t checksum = 0;
for (c = 0; c < 127; c++)
checksum += edid_data[c];
edid_data[127] = 256 - checksum;
}

4
src/vid_ddc.h Normal file
View file

@ -0,0 +1,4 @@
void ddc_init(void);
void ddc_i2c_change(int new_clock, int new_data);
int ddc_read_clock(void);
int ddc_read_data(void);

BIN
src/vid_ddc.o Normal file

Binary file not shown.

View file

@ -7,6 +7,7 @@
#include "rom.h" #include "rom.h"
#include "thread.h" #include "thread.h"
#include "video.h" #include "video.h"
#include "vid_ddc.h"
#include "vid_svga.h" #include "vid_svga.h"
#include "vid_svga_render.h" #include "vid_svga_render.h"
#include "vid_voodoo_banshee.h" #include "vid_voodoo_banshee.h"
@ -58,6 +59,7 @@ typedef struct banshee_t
uint32_t vidDesktopStartAddr; uint32_t vidDesktopStartAddr;
uint32_t vidProcCfg; uint32_t vidProcCfg;
uint32_t vidScreenSize; uint32_t vidScreenSize;
uint32_t vidSerialParallelPort;
int overlay_pix_fmt; int overlay_pix_fmt;
@ -110,6 +112,7 @@ enum
Video_hwCurLoc = 0x64, Video_hwCurLoc = 0x64,
Video_hwCurC0 = 0x68, Video_hwCurC0 = 0x68,
Video_hwCurC1 = 0x6c, Video_hwCurC1 = 0x6c,
Video_vidSerialParallelPort = 0x78,
Video_vidScreenSize = 0x98, Video_vidScreenSize = 0x98,
Video_vidOverlayStartCoords = 0x9c, Video_vidOverlayStartCoords = 0x9c,
Video_vidOverlayEndScreenCoords = 0xa0, Video_vidOverlayEndScreenCoords = 0xa0,
@ -180,6 +183,14 @@ enum
#define PIX_FORMAT_RGB24 2 #define PIX_FORMAT_RGB24 2
#define PIX_FORMAT_RGB32 3 #define PIX_FORMAT_RGB32 3
#define VIDSERIAL_DDC_DCK_W (1 << 19)
#define VIDSERIAL_DDC_DDA_W (1 << 20)
#define VIDSERIAL_DDC_DCK_R (1 << 21)
#define VIDSERIAL_DDC_DDA_R (1 << 22)
#define VIDSERIAL_I2C_SCK_W (1 << 24)
#define VIDSERIAL_I2C_SDA_W (1 << 25)
#define VIDSERIAL_I2C_SCK_R (1 << 26)
#define VIDSERIAL_I2C_SDA_R (1 << 27)
static uint32_t banshee_status(banshee_t *banshee); static uint32_t banshee_status(banshee_t *banshee);
@ -596,6 +607,12 @@ static void banshee_ext_outl(uint16_t addr, uint32_t val, void *p)
banshee->hwCurC1 = val; banshee->hwCurC1 = val;
break; break;
case Video_vidSerialParallelPort:
banshee->vidSerialParallelPort = val;
// pclog("vidSerialParallelPort: write %08x %08x %04x(%08x):%08x\n", val, val & (VIDSERIAL_DDC_DCK_W | VIDSERIAL_DDC_DDA_W), CS,cs,cpu_state.pc);
ddc_i2c_change((val & VIDSERIAL_DDC_DCK_W) ? 1 : 0, (val & VIDSERIAL_DDC_DDA_W) ? 1 : 0);
break;
case Video_vidScreenSize: case Video_vidScreenSize:
banshee->vidScreenSize = val; banshee->vidScreenSize = val;
voodoo->h_disp = (val & 0xfff) + 1; voodoo->h_disp = (val & 0xfff) + 1;
@ -824,6 +841,20 @@ static uint32_t banshee_ext_inl(uint16_t addr, void *p)
ret = banshee->hwCurC1; ret = banshee->hwCurC1;
break; break;
case Video_vidSerialParallelPort:
ret = banshee->vidSerialParallelPort & ~(VIDSERIAL_DDC_DCK_R | VIDSERIAL_DDC_DDA_R);
if ((banshee->vidSerialParallelPort & VIDSERIAL_DDC_DCK_W) && ddc_read_clock())
ret |= VIDSERIAL_DDC_DCK_R;
if ((banshee->vidSerialParallelPort & VIDSERIAL_DDC_DDA_W) && ddc_read_data())
ret |= VIDSERIAL_DDC_DDA_R;
ret = ret & ~(VIDSERIAL_I2C_SCK_R | VIDSERIAL_I2C_SDA_R);
if (banshee->vidSerialParallelPort & VIDSERIAL_I2C_SCK_W)
ret |= VIDSERIAL_I2C_SCK_R;
if (banshee->vidSerialParallelPort & VIDSERIAL_I2C_SDA_W)
ret |= VIDSERIAL_I2C_SDA_R;
// pclog("vidSerialParallelPort: read %08x %08x %04x(%08x):%08x\n", ret, ret & (VIDSERIAL_DDC_DCK_R | VIDSERIAL_DDC_DDA_R), CS,cs,cpu_state.pc);
break;
case Video_vidScreenSize: case Video_vidScreenSize:
ret = banshee->vidScreenSize; ret = banshee->vidScreenSize;
break; break;
@ -2169,6 +2200,10 @@ static void *banshee_init_common(char *fn, int has_sgram, int type, int voodoo_t
banshee->voodoo->tex_mem_w[1] = (uint16_t *)banshee->svga.vram; banshee->voodoo->tex_mem_w[1] = (uint16_t *)banshee->svga.vram;
banshee->voodoo->texture_mask = banshee->svga.vram_mask; banshee->voodoo->texture_mask = banshee->svga.vram_mask;
banshee->vidSerialParallelPort = VIDSERIAL_DDC_DCK_W | VIDSERIAL_DDC_DDA_W;
ddc_init();
return banshee; return banshee;
} }