Implemented combined PCI / memory FIFO. This is required for running Voodoo1

games / demos correctly on the Voodoo2 model. I noticed a small slowdown
(2 or 3 percent) on the Voodoo1.
This commit is contained in:
Volker Ruppert 2017-09-08 16:17:20 +00:00
parent c1d5947a80
commit da48346f9d
3 changed files with 88 additions and 31 deletions

View File

@ -158,12 +158,22 @@ void CDECL libvoodoo_LTX_plugin_fini(void)
BX_THREAD_FUNC(fifo_thread, indata)
{
Bit32u type, offset = 0, data = 0, regnum;
fifo_state *fifo;
UNUSED(indata);
while (1) {
if (fifo_wait_for_event(&fifo_wakeup)) {
while (!fifo_empty(&v->fbi.fifo)) {
type = fifo_remove(&v->fbi.fifo, &offset, &data);
BX_LOCK(fifo_mutex);
while (1) {
if (!fifo_empty(&v->fbi.fifo)) {
fifo = &v->fbi.fifo;
} else if (!fifo_empty(&v->pci.fifo)) {
fifo = &v->pci.fifo;
} else {
break;
}
type = fifo_remove(fifo, &offset, &data);
BX_UNLOCK(fifo_mutex);
switch (type) {
case FIFO_WR_REG:
if ((offset & 0x800c0) == 0x80000 && v->alt_regmap)
@ -191,7 +201,10 @@ BX_THREAD_FUNC(fifo_thread, indata)
lfb_w(offset, data, 0xffff0000);
break;
}
BX_LOCK(fifo_mutex);
}
v->pci.op_pending = 0;
BX_UNLOCK(fifo_mutex);
if (v->fbi.cmdfifo[0].enabled) {
while (v->fbi.cmdfifo[0].enabled && (v->fbi.cmdfifo[0].depth >= v->fbi.cmdfifo[0].depth_needed)) {
cmdfifo_process();
@ -645,9 +658,11 @@ void bx_voodoo_c::vertical_timer_handler(void *this_ptr)
BX_VOODOO_THIS s.vdraw.frame_start = bx_virt_timer.time_usec(0);
if (!fifo_empty(&v->fbi.fifo)) {
BX_LOCK(fifo_mutex);
if (!fifo_empty(&v->pci.fifo) || !fifo_empty(&v->fbi.fifo)) {
fifo_set_event(&fifo_wakeup);
}
BX_UNLOCK(fifo_mutex);
if (v->fbi.cmdfifo[0].cmd_ready) {
fifo_set_event(&fifo_wakeup);
}

View File

@ -1461,7 +1461,7 @@ struct _pci_state
fifo_state fifo; /* PCI FIFO */
Bit32u init_enable; /* initEnable value */
Bit8u stall_state; /* state of the system if we're stalled */
Bit8u op_pending; /* true if an operation is pending */
Bit16u op_pending; /* number of operations pending */
Bit32u fifo_mem[64*2]; /* memory backing the PCI FIFO */
};
@ -1792,8 +1792,7 @@ BX_CPP_INLINE void fifo_reset(fifo_state *f)
BX_CPP_INLINE bx_bool fifo_full(fifo_state *f)
{
bx_bool ret = (f->in + 2 == f->out || (f->in == f->size - 2 && f->out == 0));
return ret;
return (f->in + 2 == f->out || (f->in == f->size - 2 && f->out == 0));
}
@ -1820,7 +1819,6 @@ BX_CPP_INLINE void fifo_add(fifo_state *f, Bit32u offset, Bit32u data)
{
Bit32s next_in;
BX_LOCK(fifo_mutex);
if (fifo_full(f)) {
fifo_set_event(&fifo_wakeup);
BX_UNLOCK(fifo_mutex);
@ -1839,10 +1837,6 @@ BX_CPP_INLINE void fifo_add(fifo_state *f, Bit32u offset, Bit32u data)
f->base[f->in + 1] = data;
f->in = next_in;
}
if (fifo_space(f) <= 16) {
fifo_set_event(&fifo_wakeup);
}
BX_UNLOCK(fifo_mutex);
}
@ -1850,7 +1844,6 @@ BX_CPP_INLINE Bit32u fifo_remove(fifo_state *f, Bit32u *offset, Bit32u *data)
{
Bit32u type = 0;
BX_LOCK(fifo_mutex);
/* as long as we have data, we can do it */
if (f->out != f->in)
{
@ -1871,12 +1864,17 @@ BX_CPP_INLINE Bit32u fifo_remove(fifo_state *f, Bit32u *offset, Bit32u *data)
if (fifo_space(f) > 15) {
fifo_set_event(&fifo_not_full);
}
BX_UNLOCK(fifo_mutex);
return type;
}
BX_CPP_INLINE bx_bool fifo_empty(fifo_state *f)
{
return (f->in == f->out);
}
BX_CPP_INLINE bx_bool fifo_empty_locked(fifo_state *f)
{
BX_LOCK(fifo_mutex);
bx_bool ret = (f->in == f->out);
@ -1885,6 +1883,26 @@ BX_CPP_INLINE bx_bool fifo_empty(fifo_state *f)
}
BX_CPP_INLINE void fifo_move(fifo_state *f1, fifo_state *f2)
{
if (fifo_full(f2)) {
fifo_set_event(&fifo_wakeup);
BX_UNLOCK(fifo_mutex);
fifo_wait_for_event(&fifo_not_full);
BX_LOCK(fifo_mutex);
}
Bit32s items1 = fifo_items(f1);
Bit32s space2 = fifo_space(f2);
while ((items1 > 0) && (space2 > 0)) {
f2->base[f2->in++] = f1->base[f1->out++];
if (f2->in >= f2->size) f2->in = 0;
if (f1->out >= f1->size) f1->out = 0;
items1--;
space2--;
}
}
#ifndef PTR64
#define count_leading_zeros _count_leading_zeros
BX_CPP_INLINE Bit8u _count_leading_zeros(Bit32u value)

View File

@ -1307,7 +1307,7 @@ void recompute_video_memory(voodoo_state *v)
/* reset the FIFO */
fifo_reset(&v->fbi.fifo);
if (fifo_empty(&v->pci.fifo)) v->pci.op_pending = 0;
if (fifo_empty_locked(&v->pci.fifo)) v->pci.op_pending = 0;
/* reset our front/back buffers if they are out of range */
if (v->fbi.rgboffs[2] == (Bit32u)~0)
@ -2680,6 +2680,32 @@ void cmdfifo_process(void)
}
bx_bool fifo_add_common(Bit32u type_offset, Bit32u data)
{
bx_bool ret = 0;
BX_LOCK(fifo_mutex);
if (v->pci.fifo.enabled) {
fifo_add(&v->pci.fifo, type_offset, data);
ret = 1;
if (v->fbi.fifo.enabled) {
if ((fifo_space(&v->pci.fifo)/2) <= 16) {
fifo_move(&v->pci.fifo, &v->fbi.fifo);
}
if ((fifo_space(&v->fbi.fifo)/2) <= 0xe000) {
fifo_set_event(&fifo_wakeup);
}
} else {
if ((fifo_space(&v->pci.fifo)/2) <= 16) {
fifo_set_event(&fifo_wakeup);
}
}
}
BX_UNLOCK(fifo_mutex);
return ret;
}
void register_w_common(Bit32u offset, Bit32u data)
{
Bit32u regnum = (offset) & 0xff;
@ -2881,18 +2907,17 @@ void register_w_common(Bit32u offset, Bit32u data)
break;
default:
if (v->fbi.fifo.enabled) {
fifo_add(&v->fbi.fifo, FIFO_WR_REG | offset, data);
if (fifo_add_common(FIFO_WR_REG | offset, data)) {
BX_LOCK(fifo_mutex);
if ((regnum == triangleCMD) || (regnum == ftriangleCMD) || (regnum == nopCMD) ||
(regnum == fastfillCMD) || (regnum == swapbufferCMD)) {
BX_LOCK(fifo_mutex);
v->pci.op_pending++;
if (regnum == swapbufferCMD) {
v->fbi.swaps_pending++;
}
fifo_set_event(&fifo_wakeup);
BX_UNLOCK(fifo_mutex);
}
BX_UNLOCK(fifo_mutex);
} else {
register_w(offset, data, 0);
}
@ -2932,7 +2957,7 @@ Bit32u register_r(Bit32u offset)
result = 0;
/* bits 5:0 are the PCI FIFO free space */
if (fifo_empty(&v->pci.fifo))
if (fifo_empty_locked(&v->pci.fifo))
result |= 0x3f << 0;
else
{
@ -2970,7 +2995,7 @@ Bit32u register_r(Bit32u offset)
result |= v->fbi.frontbuf << 10;
/* bits 27:12 indicate memory FIFO freespace */
if (!v->fbi.fifo.enabled || fifo_empty(&v->fbi.fifo))
if (!v->fbi.fifo.enabled || fifo_empty_locked(&v->fbi.fifo))
result |= 0xffff << 12;
else
{
@ -3116,24 +3141,23 @@ Bit32u lfb_r(Bit32u offset)
void voodoo_w(Bit32u offset, Bit32u data, Bit32u mask)
{
Bit32u type;
if ((offset & (0xc00000/4)) == 0)
register_w_common(offset, data);
else if (offset & (0x800000/4)) {
if (v->fbi.fifo.enabled) {
fifo_add(&v->fbi.fifo, FIFO_WR_TEX | offset, data);
} else {
if (!fifo_add_common(FIFO_WR_TEX | offset, data)) {
texture_w(offset, data);
}
} else {
if (v->fbi.fifo.enabled) {
if (mask == 0xffffffff) {
fifo_add(&v->fbi.fifo, FIFO_WR_FBI_32 | offset, data);
} else if (mask & 1) {
fifo_add(&v->fbi.fifo, FIFO_WR_FBI_16L | offset, data);
} else {
fifo_add(&v->fbi.fifo, FIFO_WR_FBI_16H | offset, data);
}
if (mask == 0xffffffff) {
type = FIFO_WR_FBI_32;
} else if (mask & 1) {
type = FIFO_WR_FBI_16L;
} else {
type = FIFO_WR_FBI_16H;
}
if (!fifo_add_common(type | offset, data)) {
lfb_w(offset, data, mask);
}
}