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

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