diff --git a/src/Makefile.am b/src/Makefile.am index 83236d0..599fdc1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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_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 \ -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_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 \ diff --git a/src/Makefile.mingw-wx-sdl2 b/src/Makefile.mingw-wx-sdl2 index 4c13f55..3d9401f 100644 --- a/src/Makefile.mingw-wx-sdl2 +++ b/src/Makefile.mingw-wx-sdl2 @@ -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_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_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_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 \ diff --git a/src/Makefile.mingw-wx-sdl2-network b/src/Makefile.mingw-wx-sdl2-network index e58e406..7b7c632 100644 --- a/src/Makefile.mingw-wx-sdl2-network +++ b/src/Makefile.mingw-wx-sdl2-network @@ -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_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_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_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 \ diff --git a/src/vid_ddc.c b/src/vid_ddc.c new file mode 100644 index 0000000..78e40c4 --- /dev/null +++ b/src/vid_ddc.c @@ -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; +} diff --git a/src/vid_ddc.h b/src/vid_ddc.h new file mode 100644 index 0000000..7b8f8bd --- /dev/null +++ b/src/vid_ddc.h @@ -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); diff --git a/src/vid_ddc.o b/src/vid_ddc.o new file mode 100644 index 0000000..4b52766 Binary files /dev/null and b/src/vid_ddc.o differ diff --git a/src/vid_voodoo_banshee.c b/src/vid_voodoo_banshee.c index 0e95ccc..20b8292 100644 --- a/src/vid_voodoo_banshee.c +++ b/src/vid_voodoo_banshee.c @@ -7,6 +7,7 @@ #include "rom.h" #include "thread.h" #include "video.h" +#include "vid_ddc.h" #include "vid_svga.h" #include "vid_svga_render.h" #include "vid_voodoo_banshee.h" @@ -58,6 +59,7 @@ typedef struct banshee_t uint32_t vidDesktopStartAddr; uint32_t vidProcCfg; uint32_t vidScreenSize; + uint32_t vidSerialParallelPort; int overlay_pix_fmt; @@ -110,6 +112,7 @@ enum Video_hwCurLoc = 0x64, Video_hwCurC0 = 0x68, Video_hwCurC1 = 0x6c, + Video_vidSerialParallelPort = 0x78, Video_vidScreenSize = 0x98, Video_vidOverlayStartCoords = 0x9c, Video_vidOverlayEndScreenCoords = 0xa0, @@ -180,6 +183,14 @@ enum #define PIX_FORMAT_RGB24 2 #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); @@ -596,6 +607,12 @@ static void banshee_ext_outl(uint16_t addr, uint32_t val, void *p) banshee->hwCurC1 = val; 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: banshee->vidScreenSize = val; voodoo->h_disp = (val & 0xfff) + 1; @@ -824,6 +841,20 @@ static uint32_t banshee_ext_inl(uint16_t addr, void *p) ret = banshee->hwCurC1; 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: ret = banshee->vidScreenSize; 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->texture_mask = banshee->svga.vram_mask; + banshee->vidSerialParallelPort = VIDSERIAL_DDC_DCK_W | VIDSERIAL_DDC_DDA_W; + + ddc_init(); + return banshee; }