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.
This commit is contained in:
TC1995
2022-01-28 17:45:03 +01:00
parent 04ec805147
commit a2be64dcb1
6 changed files with 433 additions and 73 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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)",

View File

@@ -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",

View File

@@ -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 },

View File

@@ -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;