From a2be64dcb118981b73a42fbc9788f096a64d06ab Mon Sep 17 00:00:00 2001 From: TC1995 Date: Fri, 28 Jan 2022 17:45:03 +0100 Subject: [PATCH] Added TVP3026 clock emulation and hooked up to the corresponding S3 cards needing it. Added the SPEA Mercury Lite 928PCI-based card and its corresponding accel changes. Restored the S3 ViRGE threaded-FIFO but with small changes. --- src/include/86box/vid_svga.h | 1 + src/include/86box/video.h | 2 + src/video/vid_s3.c | 149 ++++++++++++++++------ src/video/vid_s3_virge.c | 218 +++++++++++++++++++++++++++------ src/video/vid_table.c | 2 + src/video/vid_tvp3026_ramdac.c | 134 +++++++++++++++++++- 6 files changed, 433 insertions(+), 73 deletions(-) diff --git a/src/include/86box/vid_svga.h b/src/include/86box/vid_svga.h index 4380e041b..47bb84e0f 100644 --- a/src/include/86box/vid_svga.h +++ b/src/include/86box/vid_svga.h @@ -274,6 +274,7 @@ extern void tvp3026_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, voi extern uint8_t tvp3026_ramdac_in(uint16_t addr, int rs2, int rs3, void *p, svga_t *svga); extern void tvp3026_recalctimings(void *p, svga_t *svga); extern void tvp3026_hwcursor_draw(svga_t *svga, int displine); +extern float tvp3026_getclock(int clock, void *p); #ifdef EMU_DEVICE_H extern const device_t ati68860_ramdac_device; diff --git a/src/include/86box/video.h b/src/include/86box/video.h index 3e0c74ce9..62d9e3153 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -348,6 +348,7 @@ extern const device_t s3_diamond_stealth_vram_isa_device; extern const device_t s3_ami_86c924_isa_device; extern const device_t s3_metheus_86c928_isa_device; extern const device_t s3_metheus_86c928_vlb_device; +extern const device_t s3_spea_mercury_lite_86c928_pci_device; extern const device_t s3_spea_mirage_86c801_isa_device; extern const device_t s3_spea_mirage_86c805_vlb_device; extern const device_t s3_mirocrystal_8s_805_vlb_device; @@ -394,6 +395,7 @@ extern const device_t s3_trio64v2_dx_onboard_pci_device; extern const device_t s3_virge_325_pci_device; extern const device_t s3_diamond_stealth_2000_pci_device; extern const device_t s3_diamond_stealth_3000_pci_device; +extern const device_t s3_stb_velocity_3d_pci_device; extern const device_t s3_virge_375_pci_device; extern const device_t s3_diamond_stealth_2000pro_pci_device; extern const device_t s3_virge_385_pci_device; diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index d7a961925..1796e9049 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -41,6 +41,7 @@ #define ROM_DIAMOND_STEALTH_VRAM "roms/video/s3/Diamond Stealth VRAM BIOS v2.31 U14.BIN" #define ROM_AMI_86C924 "roms/video/s3/S3924AMI.BIN" #define ROM_METHEUS_86C928 "roms/video/s3/928.VBI" +#define ROM_SPEA_MERCURY_LITE_PCI "roms/video/s3/SPEAVGA.VBI" #define ROM_SPEA_MIRAGE_86C801 "roms/video/s3/V7MIRAGE.VBI" #define ROM_SPEA_MIRAGE_86C805 "roms/video/s3/86c805pspeavlbus.BIN" #define ROM_MIROCRYSTAL8S_805 "roms/video/s3/S3_805VL_ATT20C491_miroCRYSTAL_8s_ver1.4.BIN" @@ -104,7 +105,8 @@ enum S3_PHOENIX_VISION968, S3_MIROCRYSTAL8S_805, S3_NUMBER9_9FX_531, - S3_NUMBER9_9FX_771 + S3_NUMBER9_9FX_771, + S3_SPEA_MERCURY_LITE_PCI }; @@ -113,22 +115,24 @@ enum S3_86C911 = 0x00, S3_86C924 = 0x02, S3_86C928 = 0x04, - S3_86C801 = 0x06, - S3_86C805 = 0x07, - S3_VISION964 = 0x08, - S3_VISION968 = 0x10, - S3_VISION864 = 0x18, - S3_VISION868 = 0x20, - S3_TRIO32 = 0x28, - S3_TRIO64 = 0x30, - S3_TRIO64V = 0x38, - S3_TRIO64V2 = 0x40 + S3_86C928PCI = 0x06, + S3_86C801 = 0x07, + S3_86C805 = 0x08, + S3_VISION964 = 0x18, + S3_VISION968 = 0x20, + S3_VISION864 = 0x28, + S3_VISION868 = 0x30, + S3_TRIO32 = 0x38, + S3_TRIO64 = 0x40, + S3_TRIO64V = 0x48, + S3_TRIO64V2 = 0x50 }; static video_timings_t timing_s3_86c911 = {VIDEO_ISA, 4, 4, 5, 20, 20, 35}; static video_timings_t timing_s3_86c801 = {VIDEO_ISA, 4, 4, 5, 20, 20, 35}; static video_timings_t timing_s3_86c805 = {VIDEO_BUS, 4, 4, 5, 20, 20, 35}; +static video_timings_t timing_s3_86c928pci = {VIDEO_PCI, 2, 2, 4, 26, 26, 42}; static video_timings_t timing_s3_stealth64_vlb = {VIDEO_BUS, 2, 2, 4, 26, 26, 42}; static video_timings_t timing_s3_stealth64_pci = {VIDEO_PCI, 2, 2, 4, 26, 26, 42}; static video_timings_t timing_s3_vision864_vlb = {VIDEO_BUS, 4, 4, 5, 20, 20, 35}; @@ -563,7 +567,7 @@ static void s3_accel_out_pixtrans_w(s3_t *s3, uint16_t val) { svga_t *svga = &s3->svga; - + if (s3->accel.cmd & 0x100) { switch (s3->accel.cmd & 0x600) { case 0x000: @@ -1173,7 +1177,8 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) else s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[0] << 8), s3); } else { - s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[0] << 8), s3); + if (s3->chip != S3_86C928PCI) + s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[0] << 8), s3); } break; } @@ -1197,7 +1202,7 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) } break; case 0x200: - /*Windows 95's built-in driver expects this to be loaded regardless of the byte swap bit (0xE2E9) in the 86c928*/ + /*Windows 95's built-in driver expects this to be loaded regardless of the byte swap bit (0xE2E9) in the 86c928 ISA/VLB*/ if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { if (s3->accel.cmd & 0x1000) @@ -1205,7 +1210,7 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) else s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3); } else { - if (s3->chip == S3_86C928) + if (s3->chip == S3_86C928 || s3->chip == S3_86C928PCI) s3_accel_out_pixtrans_w(s3, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8)); else { if (s3->accel.cmd & 0x1000) @@ -1214,6 +1219,15 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); } } + } else { + if (s3->chip == S3_86C928 || s3->chip == S3_86C928PCI) + s3_accel_out_pixtrans_w(s3, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8)); + else { + if (s3->accel.cmd & 0x1000) + s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3); + else + s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + } } break; case 0x400: @@ -1261,7 +1275,7 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); break; case 0x200: - /*Windows 95's built-in driver expects the upper 16 bits to be loaded instead of the whole 32-bit one, regardless of the byte swap bit (0xE2EB) in the 86c928*/ + /*Windows 95's built-in driver expects the upper 16 bits to be loaded instead of the whole 32-bit one, regardless of the byte swap bit (0xE2EB) in the 86c928 ISA/VLB card*/ if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { if (s3->accel.cmd & 0x1000) @@ -1269,7 +1283,7 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) else s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), 0, s3); } else { - if (s3->chip == S3_86C928) + if (s3->chip == S3_86C928 || s3->chip == S3_86C928PCI) s3_accel_out_pixtrans_w(s3, s3->accel.pix_trans[2] | (s3->accel.pix_trans[3] << 8)); else { if (s3->accel.cmd & 0x1000) @@ -1278,6 +1292,15 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); } } + } else { + if (s3->chip == S3_86C928 || s3->chip == S3_86C928PCI) + s3_accel_out_pixtrans_w(s3, s3->accel.pix_trans[2] | (s3->accel.pix_trans[3] << 8)); + else { + if (s3->accel.cmd & 0x1000) + s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[3] | (s3->accel.pix_trans[2] << 8) | (s3->accel.pix_trans[1] << 16) | (s3->accel.pix_trans[0] << 24), s3); + else + s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); + } } break; case 0x400: @@ -1360,7 +1383,7 @@ s3_accel_write_fifo(s3_t *s3, uint32_t addr, uint8_t val) if ((addr >= 0x08000) && (addr <= 0x0803f)) s3_pci_write(0, addr & 0xff, val, s3); } - + switch (addr & 0x1fffe) { case 0x8100: addr = 0x82e8; break; /*ALT_CURXY*/ case 0x8102: addr = 0x86e8; break; @@ -2405,8 +2428,10 @@ s3_out(uint16_t addr, uint8_t val, void *p) { case 0x3c2: if ((s3->chip == S3_VISION964) || (s3->chip == S3_VISION968) || (s3->chip == S3_86C928)) { - if (((val >> 2) & 3) != 3) - icd2061_write(svga->clock_gen, (val >> 2) & 3); + if ((s3->card_type != S3_SPEA_MERCURY_P64V) && (s3->card_type != S3_MIROVIDEO40SV_ERGO_968)) { + if (((val >> 2) & 3) != 3) + icd2061_write(svga->clock_gen, (val >> 2) & 3); + } } break; @@ -2472,6 +2497,8 @@ s3_out(uint16_t addr, uint8_t val, void *p) sc1148x_ramdac_out(addr, rs2, val, svga->ramdac, svga); } else if (s3->card_type == S3_NUMBER9_9FX_531) att498_ramdac_out(addr, rs2, val, svga->ramdac, svga); + else if ((s3->chip == S3_86C928PCI) && (s3->card_type == S3_SPEA_MERCURY_LITE_PCI)) + sc1502x_ramdac_out(addr, val, svga->ramdac, svga); else sdac_ramdac_out(addr, rs2, val, svga->ramdac, svga); return; @@ -2760,6 +2787,8 @@ s3_in(uint16_t addr, void *p) return sc1148x_ramdac_in(addr, rs2, svga->ramdac, svga); else if (s3->card_type == S3_NUMBER9_9FX_531) return att498_ramdac_in(addr, rs2, svga->ramdac, svga); + else if ((s3->chip == S3_86C928PCI) && (s3->card_type == S3_SPEA_MERCURY_LITE_PCI)) + return sc1502x_ramdac_in(addr, svga->ramdac, svga); else return sdac_ramdac_in(addr, rs2, svga->ramdac, svga); break; @@ -2880,7 +2909,7 @@ static void s3_recalctimings(svga_t *svga) if (s3->card_type == S3_MIROCRYSTAL10SD_805 || s3->card_type == S3_MIROCRYSTAL20SD_864 || s3->card_type == S3_MIROCRYSTAL20SV_964 || s3->card_type == S3_SPEA_MIRAGE_86C801 || s3->card_type == S3_SPEA_MIRAGE_86C805 || s3->card_type == S3_MIROCRYSTAL8S_805 || - s3->card_type == S3_NUMBER9_9FX_531) { + s3->card_type == S3_NUMBER9_9FX_531 || s3->card_type == S3_SPEA_MERCURY_LITE_PCI) { if (!(svga->crtc[0x5e] & 0x04)) svga->vblankstart = svga->dispend; if (svga->bpp != 32) { @@ -3006,7 +3035,8 @@ static void s3_recalctimings(svga_t *svga) svga->hdisp = s3->width; } - if (s3->card_type == S3_SPEA_MIRAGE_86C801 || s3->card_type == S3_SPEA_MIRAGE_86C805) + if (s3->card_type == S3_SPEA_MIRAGE_86C801 || s3->card_type == S3_SPEA_MIRAGE_86C805 || + s3->card_type == S3_SPEA_MERCURY_LITE_PCI) svga->hdisp = s3->width; break; case 16: @@ -3034,7 +3064,8 @@ static void s3_recalctimings(svga_t *svga) svga->hdisp = s3->width; } - if (s3->card_type == S3_SPEA_MIRAGE_86C801 || s3->card_type == S3_SPEA_MIRAGE_86C805) + if (s3->card_type == S3_SPEA_MIRAGE_86C801 || s3->card_type == S3_SPEA_MIRAGE_86C805 || + s3->card_type == S3_SPEA_MERCURY_LITE_PCI) svga->hdisp = s3->width; break; case 24: @@ -3044,6 +3075,15 @@ static void s3_recalctimings(svga_t *svga) svga->hdisp /= 3; else svga->hdisp = (svga->hdisp * 2) / 3; + + if (s3->card_type == S3_SPEA_MERCURY_LITE_PCI) { + if (s3->width == 2048) + switch (svga->dispend) { + case 480: + svga->hdisp = 640; + break; + } + } } else { if (s3->card_type == S3_MIROVIDEO40SV_ERGO_968 || s3->card_type == S3_PHOENIX_VISION968 || s3->card_type == S3_SPEA_MERCURY_P64V) @@ -3085,7 +3125,7 @@ static void s3_recalctimings(svga_t *svga) s3->width = 800; svga->hdisp = 800; break; - } + } } } } @@ -3292,6 +3332,7 @@ s3_updatemapping(s3_t *s3) case S3_TRIO64V: case S3_TRIO64V2: case S3_86C928: + case S3_86C928PCI: s3->linear_size = 0x400000; break; default: @@ -3842,8 +3883,9 @@ s3_accel_in(uint16_t port, void *p) s3_accel_start(16, 1, s3->accel.pix_trans[0], 0, s3); else s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0], s3); - } else + } else { s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0], s3); + } break; } } @@ -5235,7 +5277,6 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ /*Bit 4 of the Command register is the draw yes bit, which enables writing to memory/reading from memory when enabled. When this bit is disabled, no writing to memory/reading from memory is allowed. (This bit is almost meaningless on the NOP command)*/ - switch (cmd) { case 0: /*NOP (Short Stroke Vectors)*/ @@ -6129,8 +6170,6 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ frgd_mix = (s3->accel.frgd_mix >> 5) & 3; bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; - - while ((s3->accel.poly_cy < end_y1) && (s3->accel.poly_cy2 < end_y2)) { int y = s3->accel.poly_cy; @@ -6278,7 +6317,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ ROPMIX - if (s3->accel.cmd & 0x10) { + if (s3->accel.cmd & 0x10) { WRITE(s3->accel.dest + s3->accel.dx, out); } } @@ -6615,6 +6654,7 @@ static void s3_reset(void *priv) break; case S3_METHEUS_86C928: + case S3_SPEA_MERCURY_LITE_PCI: svga->crtc[0x5a] = 0x0a; break; @@ -6763,6 +6803,11 @@ static void *s3_init(const device_t *info) else video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c801); break; + case S3_SPEA_MERCURY_LITE_PCI: + bios_fn = ROM_SPEA_MERCURY_LITE_PCI; + chip = S3_86C928PCI; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c928pci); + break; case S3_MIROCRYSTAL20SD_864: bios_fn = ROM_MIROCRYSTAL20SD_864_VLB; chip = S3_VISION864; @@ -7159,7 +7204,20 @@ static void *s3_init(const device_t *info) svga->ramdac = device_add(&bt485_ramdac_device); svga->clock_gen = device_add(&icd2061_device); svga->getclock = icd2061_getclock; - break; + break; + + case S3_SPEA_MERCURY_LITE_PCI: + svga->decode_mask = (4 << 20) - 1; + stepping = 0xb0; /*86C928PCI*/ + s3->id = stepping; + s3->id_ext = stepping; + s3->id_ext_pci = stepping; + s3->packed_mmio = 0; + svga->crtc[0x5a] = 0x0a; + svga->ramdac = device_add(&sc1502x_ramdac_device); + svga->clock_gen = device_add(&av9194_device); + svga->getclock = av9194_getclock; + break; case S3_PARADISE_BAHAMAS64: case S3_PHOENIX_VISION864: @@ -7219,13 +7277,15 @@ static void *s3_init(const device_t *info) } if (info->local == S3_ELSAWIN2KPROX || info->local == S3_PHOENIX_VISION968 || - info->local == S3_NUMBER9_9FX_771) + info->local == S3_NUMBER9_9FX_771) { svga->ramdac = device_add(&ibm_rgb528_ramdac_device); - else + svga->clock_gen = device_add(&icd2061_device); + svga->getclock = icd2061_getclock; + } else { svga->ramdac = device_add(&tvp3026_ramdac_device); - - svga->clock_gen = device_add(&icd2061_device); - svga->getclock = icd2061_getclock; + svga->clock_gen = svga->ramdac; + svga->getclock = tvp3026_getclock; + } break; case S3_NUMBER9_9FX_531: @@ -7380,6 +7440,11 @@ static int s3_metheus_86c928_available(void) return rom_present(ROM_METHEUS_86C928); } +static int s3_spea_mercury_lite_pci_available(void) +{ + return rom_present(ROM_SPEA_MERCURY_LITE_PCI); +} + static int s3_bahamas64_available(void) { return rom_present(ROM_PARADISE_BAHAMAS64); @@ -7796,6 +7861,20 @@ const device_t s3_metheus_86c928_vlb_device = s3_standard_config }; +const device_t s3_spea_mercury_lite_86c928_pci_device = +{ + "S3 86c928 PCI (SPEA Mercury Lite)", + DEVICE_PCI, + S3_SPEA_MERCURY_LITE_PCI, + s3_init, + s3_close, + s3_reset, + { s3_spea_mercury_lite_pci_available }, + s3_speed_changed, + s3_force_redraw, + s3_standard_config +}; + const device_t s3_mirocrystal_20sd_864_vlb_device = { "S3 Vision864 VLB (MiroCRYSTAL 20SD)", diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index e0e8b0e2e..fb589677f 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -61,7 +61,7 @@ static int dither[4][4] = #define FIFO_ENTRY_SIZE (1 << 31) #define FIFO_ENTRIES (virge->fifo_write_idx - virge->fifo_read_idx) -#define FIFO_FULL ((virge->fifo_write_idx - virge->fifo_read_idx) >= FIFO_SIZE) +#define FIFO_FULL ((virge->fifo_write_idx - virge->fifo_read_idx) >= (FIFO_SIZE - 4)) #define FIFO_EMPTY (virge->fifo_read_idx == virge->fifo_write_idx) #define FIFO_TYPE 0xff000000 @@ -70,6 +70,7 @@ static int dither[4][4] = #define ROM_VIRGE_325 "roms/video/s3virge/86c325.bin" #define ROM_DIAMOND_STEALTH3D_2000 "roms/video/s3virge/s3virge.bin" #define ROM_DIAMOND_STEALTH3D_3000 "roms/video/s3virge/diamondstealth3000.vbi" +#define ROM_STB_VELOCITY_3D "roms/video/s3virge/stb_velocity3d_110.BIN" #define ROM_VIRGE_DX "roms/video/s3virge/86c375_1.bin" #define ROM_DIAMOND_STEALTH3D_2000PRO "roms/video/s3virge/virgedxdiamond.vbi" #define ROM_VIRGE_GX "roms/video/s3virge/86c375_4.bin" @@ -82,6 +83,7 @@ enum S3_VIRGE_325, S3_DIAMOND_STEALTH3D_2000, S3_DIAMOND_STEALTH3D_3000, + S3_STB_VELOCITY_3D, S3_VIRGE_DX, S3_DIAMOND_STEALTH3D_2000PRO, S3_VIRGE_GX, @@ -288,7 +290,6 @@ typedef struct virge_t int sec_x, sec_y, sec_w, sec_h; } streams; - int fifo_slot; uint8_t cmd_dma; uint8_t dma_bs; uint32_t cmd_dma_base; @@ -302,6 +303,10 @@ typedef struct virge_t fifo_entry_t fifo[FIFO_SIZE]; volatile int fifo_read_idx, fifo_write_idx; + thread_t *fifo_thread; + event_t *wake_fifo_thread; + event_t *fifo_not_full_event; + int virge_busy, local; uint8_t subsys_stat, subsys_cntl, advfunc_cntl; @@ -417,6 +422,11 @@ s3_virge_tri_timer(void *p) thread_set_event(virge->wake_render_thread); /*Wake up FIFO thread if moving from idle*/ } +static __inline void +wake_fifo_thread(virge_t *virge) +{ + thread_set_event(virge->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} static void queue_triangle(virge_t *virge) @@ -970,7 +980,8 @@ static void s3_virge_updatemapping(virge_t *virge) mem_mapping_disable(&virge->new_mmio_mapping); } -static void s3_virge_vblank_start(svga_t *svga) +static void +s3_virge_vblank_start(svga_t *svga) { virge_t *virge = (virge_t *)svga->p; @@ -978,6 +989,16 @@ static void s3_virge_vblank_start(svga_t *svga) s3_virge_update_irqs(virge); } +static void +s3_virge_wait_fifo_idle(virge_t *virge) +{ + while (!FIFO_EMPTY) + { + wake_fifo_thread(virge); + thread_wait_event(virge->fifo_not_full_event, 1); + } +} + static uint8_t s3_virge_mmio_read(uint32_t addr, void *p) { @@ -989,14 +1010,12 @@ s3_virge_mmio_read(uint32_t addr, void *p) switch (addr & 0xffff) { case 0x8505: - ret = 0; - if (virge->s3d_busy || virge->fifo_slot) { - ret = 0x10; - } else { - ret = 0x30; - } - if (virge->fifo_slot) - virge->fifo_slot--; + if (virge->s3d_busy || virge->virge_busy || !FIFO_EMPTY) + ret = 0x10; + else + ret = 0x10 | (1 << 5); + if (!virge->virge_busy) + wake_fifo_thread(virge); return ret; case 0x83b0: case 0x83b1: case 0x83b2: case 0x83b3: @@ -1014,6 +1033,7 @@ s3_virge_mmio_read(uint32_t addr, void *p) return s3_virge_in(addr & 0x3ff, virge); case 0x859c: + s3_virge_wait_fifo_idle(virge); return virge->cmd_dma; case 0xff20: case 0xff21: @@ -1030,22 +1050,21 @@ static uint16_t s3_virge_mmio_read_w(uint32_t addr, void *p) { virge_t *virge = (virge_t *)p; - uint32_t ret = 0xffff; + uint16_t ret = 0xffff; s3_virge_log("[%04X:%08X]: MMIO ReadW addr = %04x\n", CS, cpu_state.pc, addr & 0xfffe); switch (addr & 0xfffe) { case 0x8504: - if (!virge->fifo_slot) + if (FIFO_EMPTY) virge->subsys_stat |= INT_FIFO_EMP; ret |= virge->subsys_stat; - if (virge->fifo_slot) - virge->fifo_slot--; ret |= 0x30; /*A bit of a workaround at the moment.*/ s3_virge_update_irqs(virge); - return ret; + return ret; case 0x859c: + s3_virge_wait_fifo_idle(virge); return virge->cmd_dma; default: @@ -1134,78 +1153,91 @@ s3_virge_mmio_read_l(uint32_t addr, void *p) break; case 0x8504: - if (virge->s3d_busy || virge->fifo_slot) { + if (virge->s3d_busy || virge->virge_busy || !FIFO_EMPTY) ret = (0x10 << 8); - } else { + else ret = (0x10 << 8) | (1 << 13); - if (!virge->s3d_busy) - virge->subsys_stat |= INT_3DF_EMP; - if (!virge->fifo_slot) - virge->subsys_stat |= INT_FIFO_EMP; - } ret |= virge->subsys_stat; - if (virge->fifo_slot) - virge->fifo_slot--; - s3_virge_update_irqs(virge); + if (!virge->virge_busy) + wake_fifo_thread(virge); dmahdr->dblword_read = 0; dmahdr->dblword_write = 0; break; case 0x8590: + s3_virge_wait_fifo_idle(virge); ret = virge->cmd_dma_base; break; case 0x8594: + s3_virge_wait_fifo_idle(virge); break; case 0x8598: + s3_virge_wait_fifo_idle(virge); ret = virge->dma_ptr; break; case 0x859c: + s3_virge_wait_fifo_idle(virge); ret = virge->cmd_dma; break; case 0xa4d4: + s3_virge_wait_fifo_idle(virge); ret = virge->s3d.src_base; break; case 0xa4d8: + s3_virge_wait_fifo_idle(virge); ret = virge->s3d.dest_base; break; case 0xa4dc: + s3_virge_wait_fifo_idle(virge); ret = (virge->s3d.clip_l << 16) | virge->s3d.clip_r; break; case 0xa4e0: + s3_virge_wait_fifo_idle(virge); ret = (virge->s3d.clip_t << 16) | virge->s3d.clip_b; break; case 0xa4e4: + s3_virge_wait_fifo_idle(virge); ret = (virge->s3d.dest_str << 16) | virge->s3d.src_str; break; case 0xa4e8: case 0xace8: + s3_virge_wait_fifo_idle(virge); ret = virge->s3d.mono_pat_0; break; case 0xa4ec: case 0xacec: + s3_virge_wait_fifo_idle(virge); ret = virge->s3d.mono_pat_1; break; case 0xa4f0: + s3_virge_wait_fifo_idle(virge); ret = virge->s3d.pat_bg_clr; break; case 0xa4f4: + s3_virge_wait_fifo_idle(virge); ret = virge->s3d.pat_fg_clr; break; case 0xa4f8: + s3_virge_wait_fifo_idle(virge); ret = virge->s3d.src_bg_clr; break; case 0xa4fc: + s3_virge_wait_fifo_idle(virge); ret = virge->s3d.src_fg_clr; break; case 0xa500: + s3_virge_wait_fifo_idle(virge); ret = virge->s3d.cmd_set; break; case 0xa504: + s3_virge_wait_fifo_idle(virge); ret = (virge->s3d.r_width << 16) | virge->s3d.r_height; break; case 0xa508: + s3_virge_wait_fifo_idle(virge); ret = (virge->s3d.rsrc_x << 16) | virge->s3d.rsrc_y; break; case 0xa50c: + s3_virge_wait_fifo_idle(virge); ret = (virge->s3d.rdest_x << 16) | virge->s3d.rdest_y; break; @@ -1242,14 +1274,96 @@ s3_virge_mmio_read_l(uint32_t addr, void *p) return ret; } +static void +fifo_thread(void *param) +{ + virge_t *virge = (virge_t *)param; -static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p) + while (virge->fifo_thread_run) + { + thread_set_event(virge->fifo_not_full_event); + thread_wait_event(virge->wake_fifo_thread, -1); + thread_reset_event(virge->wake_fifo_thread); + virge->virge_busy = 1; + while (!FIFO_EMPTY) + { + uint64_t start_time = plat_timer_read(); + uint64_t end_time; + uint32_t addr, val; + fifo_entry_t *fifo = &virge->fifo[virge->fifo_read_idx & FIFO_MASK]; + addr = fifo->addr_type & FIFO_ADDR; + val = fifo->val; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITE_BYTE: + if ((addr & 0xfffc) < 0x8000) + s3_virge_bitblt(virge, 8, val); + break; + case FIFO_WRITE_WORD: + if ((addr & 0xfffc) < 0x8000) + { + if (virge->s3d.cmd_set & CMD_SET_MS) + s3_virge_bitblt(virge, 16, ((val >> 8) | (val << 8)) << 16); + else + s3_virge_bitblt(virge, 16, val); + } + break; + case FIFO_WRITE_DWORD: + if ((addr & 0xfffc) < 0x8000) + { + if (virge->s3d.cmd_set & CMD_SET_MS) + s3_virge_bitblt(virge, 32, ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24)); + else + s3_virge_bitblt(virge, 32, val); + } + break; + } + + virge->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(virge->fifo_not_full_event); + + end_time = plat_timer_read(); + virge_time += end_time - start_time; + } + virge->virge_busy = 0; + virge->subsys_stat |= INT_FIFO_EMP | INT_3DF_EMP; + s3_virge_update_irqs(virge); + } +} + +static void +s3_virge_queue(virge_t *virge, uint32_t addr, uint32_t val, uint32_t type) +{ + fifo_entry_t *fifo = &virge->fifo[virge->fifo_write_idx & FIFO_MASK]; + + if (FIFO_FULL) + { + thread_reset_event(virge->fifo_not_full_event); + if (FIFO_FULL) + thread_wait_event(virge->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } + + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; + + virge->fifo_write_idx++; + + if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) + wake_fifo_thread(virge); +} + +static void +s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p) { virge_t *virge = (virge_t *)p; s3_virge_log("MMIO WriteB addr = %04x, val = %02x\n", addr & 0xffff, val); if ((addr & 0xffff) < 0x8000) { - s3_virge_bitblt(virge, 8, val); + s3_virge_queue(virge, addr, val, FIFO_WRITE_BYTE); } else { switch (addr & 0xffff) { case 0x83b0: case 0x83b1: case 0x83b2: case 0x83b3: @@ -1286,10 +1400,7 @@ s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *p) s3_virge_log("[%04X:%08X]: MMIO WriteW addr = %04x, val = %04x\n", CS, cpu_state.pc, addr & 0xfffe, val); if ((addr & 0xfffe) < 0x8000) { - if (virge->s3d.cmd_set & CMD_SET_MS) - s3_virge_bitblt(virge, 16, ((val >> 8) | (val << 8)) << 16); - else - s3_virge_bitblt(virge, 16, val); + s3_virge_queue(virge, addr, val, FIFO_WRITE_WORD); } else { if ((addr & 0xfffe) == 0x83d4) { s3_virge_mmio_write(addr, val, virge); @@ -1310,17 +1421,19 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p) s3_virge_log("MMIO WriteL addr = %04x, val = %08x\n", addr & 0xfffc, val); if ((addr & 0xfffc) < 0x8000) { + if ((addr & 0xe000) == 0) { if (virge->s3d.cmd_set & CMD_SET_MS) s3_virge_bitblt(virge, 32, ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24)); else - s3_virge_bitblt(virge, 32, val); + s3_virge_bitblt(virge, 32, val); + } else { + s3_virge_queue(virge, addr, val, FIFO_WRITE_DWORD); + } if (virge->cmd_dma) { dmahdr->datatype = 1; } } else { - if ((addr & 0xfffc) >= 0xa000) - virge->fifo_slot++; if (virge->cmd_dma) { dmahdr->datatype = 0; } @@ -3875,6 +3988,7 @@ static void s3_virge_reset(void *priv) virge->svga.crtc[0x59] = 0x70; break; case S3_DIAMOND_STEALTH3D_3000: + case S3_STB_VELOCITY_3D: virge->svga.crtc[0x59] = 0x70; break; case S3_VIRGE_GX2: @@ -3950,6 +4064,9 @@ static void *s3_virge_init(const device_t *info) case S3_DIAMOND_STEALTH3D_3000: bios_fn = ROM_DIAMOND_STEALTH3D_3000; break; + case S3_STB_VELOCITY_3D: + bios_fn = ROM_STB_VELOCITY_3D; + break; case S3_VIRGE_DX: bios_fn = ROM_VIRGE_DX; break; @@ -4041,6 +4158,7 @@ static void *s3_virge_init(const device_t *info) video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_diamond_stealth3d_2000_pci); break; case S3_DIAMOND_STEALTH3D_3000: + case S3_STB_VELOCITY_3D: virge->svga.decode_mask = (8 << 20) - 1; virge->virge_id_high = 0x88; virge->virge_id_low = 0x3d; @@ -4135,6 +4253,11 @@ static void *s3_virge_init(const device_t *info) virge->render_thread_run = 1; virge->render_thread = thread_create(render_thread, virge); + virge->wake_fifo_thread = thread_create_event(); + virge->fifo_not_full_event = thread_create_event(); + virge->fifo_thread_run = 1; + virge->fifo_thread = thread_create(fifo_thread, virge); + timer_add(&virge->tri_timer, s3_virge_tri_timer, virge, 0); virge->local = info->local; @@ -4153,6 +4276,12 @@ static void s3_virge_close(void *p) thread_destroy_event(virge->wake_main_thread); thread_destroy_event(virge->wake_render_thread); + virge->fifo_thread_run = 0; + thread_set_event(virge->wake_fifo_thread); + thread_wait(virge->fifo_thread); + thread_destroy_event(virge->wake_fifo_thread); + thread_destroy_event(virge->fifo_not_full_event); + svga_close(&virge->svga); ddc_close(virge->ddc); @@ -4176,6 +4305,11 @@ static int s3_virge_988_diamond_available(void) return rom_present(ROM_DIAMOND_STEALTH3D_3000); } +static int s3_virge_988_stb_available(void) +{ + return rom_present(ROM_STB_VELOCITY_3D); +} + static int s3_virge_375_available(void) { return rom_present(ROM_VIRGE_DX); @@ -4302,6 +4436,20 @@ const device_t s3_diamond_stealth_3000_pci_device = s3_virge_config }; +const device_t s3_stb_velocity_3d_pci_device = +{ + "S3 ViRGE/VX (STB Velocity 3D) PCI", + DEVICE_PCI, + S3_STB_VELOCITY_3D, + s3_virge_init, + s3_virge_close, + s3_virge_reset, + { s3_virge_988_stb_available }, + s3_virge_speed_changed, + s3_virge_force_redraw, + s3_virge_config +}; + const device_t s3_virge_375_pci_device = { "S3 ViRGE/DX (375) PCI", diff --git a/src/video/vid_table.c b/src/video/vid_table.c index d89365255..4cccea754 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -138,6 +138,7 @@ video_cards[] = { { "cl_gd5480_pci", &gd5480_pci_device }, { "ctl3d_banshee_pci", &creative_voodoo_banshee_device }, { "stealth32_pci", &et4000w32p_pci_device }, + { "spea_mercurylite_pci", &s3_spea_mercury_lite_86c928_pci_device }, { "stealth64v_pci", &s3_diamond_stealth64_964_pci_device }, { "elsawin2kprox_964_pci", &s3_elsa_winner2000_pro_x_964_pci_device }, { "mirocrystal20sv_pci", &s3_mirocrystal_20sv_964_pci_device }, @@ -160,6 +161,7 @@ video_cards[] = { { "virge325_pci", &s3_virge_325_pci_device }, { "stealth3d_2000_pci", &s3_diamond_stealth_2000_pci_device }, { "stealth3d_3000_pci", &s3_diamond_stealth_3000_pci_device }, + { "stb_velocity3d_pci", &s3_stb_velocity_3d_pci_device }, { "virge375_pci", &s3_virge_375_pci_device }, { "stealth3d_2000pro_pci", &s3_diamond_stealth_2000pro_pci_device }, { "virge385_pci", &s3_virge_385_pci_device }, diff --git a/src/video/vid_tvp3026_ramdac.c b/src/video/vid_tvp3026_ramdac.c index 926921946..c3fc85655 100644 --- a/src/video/vid_tvp3026_ramdac.c +++ b/src/video/vid_tvp3026_ramdac.c @@ -47,6 +47,12 @@ typedef struct uint8_t misc; uint8_t type; uint8_t mode; + uint8_t pll_addr; + uint8_t clock_sel; + struct + { + uint8_t m, n, p; + } pix, mem, loop; } tvp3026_ramdac_t; static void @@ -96,7 +102,6 @@ tvp3026_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, void *p, svga_t rs |= (!!rs2 << 2); rs |= (!!rs3 << 3); - switch (rs) { case 0x00: /* Palette Write Index Register (RS value = 0000) */ ramdac->ind_idx = val; @@ -152,7 +157,7 @@ tvp3026_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, void *p, svga_t svga->dac_hwcursor.xsize = svga->dac_hwcursor.ysize = 64; svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.xsize; svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.ysize; - svga->dac_hwcursor.ena = ((val & 0x03) != 0); + svga->dac_hwcursor.ena = !!(val & 0x03); ramdac->mode = val & 0x03; } break; @@ -163,7 +168,7 @@ tvp3026_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, void *p, svga_t svga->dac_hwcursor.xsize = svga->dac_hwcursor.ysize = 64; svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.xsize; svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.ysize; - svga->dac_hwcursor.ena = ((val & 0x03) != 0); + svga->dac_hwcursor.ena = !!(val & 0x03); ramdac->mode = val & 0x03; break; case 0x0f: /* Latch Control */ @@ -177,6 +182,9 @@ tvp3026_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, void *p, svga_t ramdac->mcr = val; tvp3026_set_bpp(ramdac, svga); break; + case 0x1a: /* Clock Selection */ + ramdac->clock_sel = val; + break; case 0x1c: /* Palette-Page Register */ ramdac->ppr = val; break; @@ -187,6 +195,51 @@ tvp3026_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, void *p, svga_t ramdac->misc = val; svga->ramdac_type = (val & 0x08) ? RAMDAC_8BIT : RAMDAC_6BIT; break; + case 0x2c: /* PLL Address */ + ramdac->pll_addr = val; + break; + case 0x2d: /* Pixel clock PLL data */ + switch (ramdac->pll_addr & 3) { + case 0: + ramdac->pix.n = val; + break; + case 1: + ramdac->pix.m = val; + break; + case 2: + ramdac->pix.p = val; + break; + } + ramdac->pll_addr = ((ramdac->pll_addr + 1) & 3) | (ramdac->pll_addr & 0xfc); + break; + case 0x2e: /* Memory Clock PLL Data */ + switch ((ramdac->pll_addr >> 2) & 3) { + case 0: + ramdac->mem.n = val; + break; + case 1: + ramdac->mem.m = val; + break; + case 2: + ramdac->mem.p = val; + break; + } + ramdac->pll_addr = ((ramdac->pll_addr + 4) & 0x0c) | (ramdac->pll_addr & 0xf3); + break; + case 0x2f: /* Loop Clock PLL Data */ + switch ((ramdac->pll_addr >> 4) & 3) { + case 0: + ramdac->loop.n = val; + break; + case 1: + ramdac->loop.m = val; + break; + case 2: + ramdac->loop.p = val; + break; + } + ramdac->pll_addr = ((ramdac->pll_addr + 0x10) & 0x30) | (ramdac->pll_addr & 0xcf); + break; case 0x39: /* MCLK/Loop Clock Control */ ramdac->mclk = val; break; @@ -292,6 +345,9 @@ tvp3026_ramdac_in(uint16_t addr, int rs2, int rs3, void *p, svga_t *svga) case 0x19: /* Multiplex Control */ temp = ramdac->mcr; break; + case 0x1a: /* Clock Selection */ + temp = ramdac->clock_sel; + break; case 0x1c: /* Palette-Page Register */ temp = ramdac->ppr; break; @@ -301,6 +357,54 @@ tvp3026_ramdac_in(uint16_t addr, int rs2, int rs3, void *p, svga_t *svga) case 0x1e: /* Miscellaneous Control */ temp = ramdac->misc; break; + case 0x2c: /* PLL Address */ + temp = ramdac->pll_addr; + break; + case 0x2d: /* Pixel clock PLL data */ + switch (ramdac->pll_addr & 3) { + case 0: + temp = ramdac->pix.n; + break; + case 1: + temp = ramdac->pix.m; + break; + case 2: + temp = ramdac->pix.p; + break; + case 3: + temp = 0x40; /*PLL locked to frequency*/ + break; + } + break; + case 0x2e: /* Memory Clock PLL Data */ + switch ((ramdac->pll_addr >> 2) & 3) { + case 0: + temp = ramdac->mem.n; + break; + case 1: + temp = ramdac->mem.m; + break; + case 2: + temp = ramdac->mem.p; + break; + case 3: + temp = 0x40; /*PLL locked to frequency*/ + break; + } + break; + case 0x2f: /* Loop Clock PLL Data */ + switch ((ramdac->pll_addr >> 4) & 3) { + case 0: + temp = ramdac->loop.n; + break; + case 1: + temp = ramdac->loop.m; + break; + case 2: + temp = ramdac->loop.p; + break; + } + break; case 0x39: /* MCLK/Loop Clock Control */ temp = ramdac->mclk; break; @@ -436,6 +540,29 @@ tvp3026_hwcursor_draw(svga_t *svga, int displine) } +float +tvp3026_getclock(int clock, void *p) +{ + tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) p; + int n, m, pl; + float f_vco, f_pll; + + if (clock == 0) + return 25175000.0; + if (clock == 1) + return 28322000.0; + +/*Fvco = 8 x Fref x (65 - M) / (65 - N)*/ +/*Fpll = Fvco / 2^P*/ + n = ramdac->pix.n & 0x3f; + m = ramdac->pix.m & 0x3f; + pl = ramdac->pix.p & 0x03; + f_vco = 8.0 * 14318184 * (float)(65 - m) / (float)(65 - n); + f_pll = f_vco / (float)(1 << pl); + + return f_pll; +} + void * tvp3026_ramdac_init(const device_t *info) { @@ -447,6 +574,7 @@ tvp3026_ramdac_init(const device_t *info) ramdac->latch_cntl = 0x06; ramdac->true_color = 0x80; ramdac->mcr = 0x98; + ramdac->clock_sel = 0x07; ramdac->mclk = 0x18; return ramdac;