Implemented memory FIFO to speed up the Voodoo1 emulation. The PCI FIFO with

it's 64 entries is still not present, since it makes the emulation a few
percent slower due to the overhead of the FIFO code. The memory FIFO has 64k
entries and makes a speedup of around 75 % possible.
This commit is contained in:
Volker Ruppert 2017-09-01 17:30:49 +00:00
parent ea8bfca53f
commit 1f85292418
3 changed files with 166 additions and 64 deletions

View File

@ -157,10 +157,36 @@ void CDECL libvoodoo_LTX_plugin_fini(void)
BX_THREAD_FUNC(fifo_thread, indata)
{
Bit32u type, offset = 0, data = 0, regnum;
UNUSED(indata);
while (1) {
if (fifo_wait_for_event(&fifo_wakeup)) {
// TODO: process PCI FIFO / memory FIFO data here
// TODO: also process memory FIFO data here
while (!fifo_empty(&v->fbi.fifo)) {
type = fifo_remove(&v->fbi.fifo, &offset, &data);
switch (type) {
case FIFO_WR_REG:
if ((offset & 0x800c0) == 0x80000 && v->alt_regmap)
regnum = register_alias_map[offset & 0x3f];
else
regnum = offset & 0xff;
register_w(offset, data, 0);
if ((regnum == triangleCMD) || (regnum == ftriangleCMD) || (regnum == nopCMD) ||
(regnum == fastfillCMD) || (regnum == swapbufferCMD)) {
BX_LOCK(fifo_mutex);
v->pci.op_pending--;
BX_UNLOCK(fifo_mutex);
}
break;
case FIFO_WR_FBI:
lfb_w(offset, data, 0xffffffff);
break;
case FIFO_WR_TEX:
texture_w(offset, data);
break;
}
}
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();
@ -187,14 +213,18 @@ bx_voodoo_c::bx_voodoo_c()
bx_voodoo_c::~bx_voodoo_c()
{
BX_THREAD_KILL(fifo_thread_var);
BX_FINI_MUTEX(fifo_mutex);
if (BX_VOODOO_THIS s.model == VOODOO_2) {
BX_FINI_MUTEX(cmdfifo_mutex);
}
#ifdef WIN32
CloseHandle(fifo_wakeup.event);
CloseHandle(fifo_not_full.event);
#else
pthread_cond_destroy(&fifo_wakeup.cond);
pthread_mutex_destroy(&fifo_wakeup.mutex);
pthread_cond_destroy(&fifo_not_full.cond);
pthread_mutex_destroy(&fifo_not_full.mutex);
#endif
if (v != NULL) {
free(v->fbi.ram);
@ -249,16 +279,21 @@ void bx_voodoo_c::init(void)
voodoo_init(BX_VOODOO_THIS s.model);
BX_INIT_MUTEX(fifo_mutex);
if (BX_VOODOO_THIS s.model == VOODOO_2) {
v->fbi.cmdfifo[0].depth_needed = BX_MAX_BIT32U;
BX_INIT_MUTEX(cmdfifo_mutex);
}
#ifdef WIN32
fifo_wakeup.event = CreateEvent(NULL, FALSE, FALSE, "fifo_wakeup");
fifo_not_full.event = CreateEvent(NULL, FALSE, FALSE, "fifo_not_full");
#else
pthread_cond_init(&fifo_wakeup.cond, NULL);
pthread_mutex_init(&fifo_wakeup.mutex, NULL);
pthread_cond_init(&fifo_not_full.cond, NULL);
pthread_mutex_init(&fifo_not_full.mutex, NULL);
#endif
fifo_set_event(&fifo_not_full);
BX_THREAD_CREATE(fifo_thread, this, fifo_thread_var);
BX_INFO(("3dfx Voodoo Graphics adapter (model=%s) initialized",
@ -604,6 +639,9 @@ 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)) {
fifo_set_event(&fifo_wakeup);
}
if (v->fbi.cmdfifo[0].cmd_ready) {
fifo_set_event(&fifo_wakeup);
}
@ -770,8 +808,10 @@ void bx_voodoo_c::pci_write_handler(Bit8u address, Bit32u value, unsigned io_len
case 0x43:
if (((address+i) == 0x40) && ((value8 ^ oldval) & 0x02)) {
v->pci.fifo.enabled = ((value8 & 0x02) > 0);
BX_INFO(("PCI FIFO now %sabled (not implemented yet)",
v->pci.fifo.enabled ? "en":"dis"));
if (!v->pci.fifo.enabled && !fifo_empty(&v->pci.fifo)) {
fifo_set_event(&fifo_wakeup);
}
BX_DEBUG(("PCI FIFO now %sabled (not implemented)", v->pci.fifo.enabled ? "en":"dis"));
}
if (((address+i) == 0x41) && (BX_VOODOO_THIS s.model == VOODOO_2)) {
value8 &= 0x0f;

View File

@ -1733,7 +1733,9 @@ struct _voodoo_state
// FIFO event handling
BX_MUTEX(fifo_mutex);
fifo_event_t fifo_wakeup;
fifo_event_t fifo_not_full;
void fifo_set_event(fifo_event_t *fifo_ev)
@ -1771,67 +1773,25 @@ bx_bool fifo_wait_for_event(fifo_event_t *fifo_ev)
*
*************************************/
/* fifo content defines */
#define FIFO_TYPES (7 << 29)
#define FIFO_WR_REG (1 << 29)
#define FIFO_WR_FBI (2 << 29)
#define FIFO_WR_TEX (4 << 29)
BX_CPP_INLINE void fifo_reset(fifo_state *f)
{
BX_LOCK(fifo_mutex);
f->in = f->out = 0;
fifo_set_event(&fifo_not_full);
BX_UNLOCK(fifo_mutex);
}
BX_CPP_INLINE void fifo_add(fifo_state *f, Bit32u data)
BX_CPP_INLINE bx_bool fifo_full(fifo_state *f)
{
Bit32s next_in;
/* compute the value of 'in' after we add this item */
next_in = f->in + 1;
if (next_in >= f->size)
next_in = 0;
/* as long as it's not equal to the output pointer, we can do it */
if (next_in != f->out)
{
f->base[f->in] = data;
f->in = next_in;
}
}
BX_CPP_INLINE Bit32u fifo_remove(fifo_state *f)
{
Bit32u data = 0xffffffff;
/* as long as we have data, we can do it */
if (f->out != f->in)
{
Bit32s next_out;
/* fetch the data */
data = f->base[f->out];
/* advance the output pointer */
next_out = f->out + 1;
if (next_out >= f->size)
next_out = 0;
f->out = next_out;
}
return data;
}
BX_CPP_INLINE Bit32u fifo_peek(fifo_state *f)
{
return f->base[f->out];
}
BX_CPP_INLINE int fifo_empty(fifo_state *f)
{
return (f->in == f->out);
}
BX_CPP_INLINE int fifo_full(fifo_state *f)
{
return (f->in + 1 == f->out || (f->in == f->size - 1 && f->out == 0));
bx_bool ret = (f->in + 2 == f->out || (f->in == f->size - 2 && f->out == 0));
return ret;
}
@ -1849,7 +1809,77 @@ BX_CPP_INLINE Bit32s fifo_space(fifo_state *f)
Bit32s items = f->in - f->out;
if (items < 0)
items += f->size;
return f->size - 1 - items;
Bit32s fspace = f->size - 1 - items;
return fspace;
}
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);
fifo_wait_for_event(&fifo_not_full);
BX_LOCK(fifo_mutex);
}
/* compute the value of 'in' after we add this item */
next_in = f->in + 2;
if (next_in >= f->size)
next_in = 0;
/* as long as it's not equal to the output pointer, we can do it */
if (next_in != f->out)
{
f->base[f->in] = offset;
f->base[f->in + 1] = data;
f->in = next_in;
}
if (fifo_space(f) <= 16) {
fifo_set_event(&fifo_wakeup);
}
BX_UNLOCK(fifo_mutex);
}
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)
{
Bit32s next_out;
/* fetch the data */
*offset = f->base[f->out];
type = *offset & FIFO_TYPES;
*offset &= 0xffffff;
*data = f->base[f->out + 1];
/* advance the output pointer */
next_out = f->out + 2;
if (next_out >= f->size)
next_out = 0;
f->out = next_out;
}
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)
{
BX_LOCK(fifo_mutex);
bx_bool ret = (f->in == f->out);
BX_UNLOCK(fifo_mutex);
return ret;
}

View File

@ -2789,7 +2789,7 @@ void register_w_common(Bit32u offset, Bit32u data)
Voodoo_Output_Enable(data & 1);
if (v->fbi.fifo.enabled != FBIINIT0_ENABLE_MEMORY_FIFO(data)) {
v->fbi.fifo.enabled = FBIINIT0_ENABLE_MEMORY_FIFO(data);
BX_INFO(("memory FIFO now %sabled (not implemented yet)",
BX_INFO(("memory FIFO now %sabled",
v->fbi.fifo.enabled ? "en" : "dis"));
}
v->reg[fbiInit0].u = data;
@ -2875,7 +2875,21 @@ void register_w_common(Bit32u offset, Bit32u data)
break;
default:
register_w(offset, data, 0);
if (v->fbi.fifo.enabled) {
fifo_add(&v->fbi.fifo, FIFO_WR_REG | offset, data);
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);
}
} else {
register_w(offset, data, 0);
}
}
}
@ -2917,7 +2931,9 @@ Bit32u register_r(Bit32u offset)
result |= 0x3f << 0;
else
{
BX_LOCK(fifo_mutex);
int temp = fifo_space(&v->pci.fifo)/2;
BX_UNLOCK(fifo_mutex);
if (temp > 0x3f)
temp = 0x3f;
result |= temp << 0;
@ -2953,7 +2969,9 @@ Bit32u register_r(Bit32u offset)
result |= 0xffff << 12;
else
{
BX_LOCK(fifo_mutex);
int temp = fifo_space(&v->fbi.fifo)/2;
BX_UNLOCK(fifo_mutex);
if (temp > 0xffff)
temp = 0xffff;
result |= temp << 12;
@ -3095,10 +3113,19 @@ void voodoo_w(Bit32u offset, Bit32u data, Bit32u mask)
{
if ((offset & (0xc00000/4)) == 0)
register_w_common(offset, data);
else if (offset & (0x800000/4))
texture_w(offset, data);
else
lfb_w(offset, data, mask);
else if (offset & (0x800000/4)) {
if (v->fbi.fifo.enabled) {
fifo_add(&v->fbi.fifo, FIFO_WR_TEX | offset, data);
} else {
texture_w(offset, data);
}
} else {
if (v->fbi.fifo.enabled) {
fifo_add(&v->fbi.fifo, FIFO_WR_FBI | offset, data);
} else {
lfb_w(offset, data, mask);
}
}
}
Bit32u voodoo_r(Bit32u offset)
@ -3230,6 +3257,11 @@ void voodoo_init(Bit8u _type)
v->dac.clk0_n = 0x02;
v->dac.clk0_p = 0x03;
/* set up the PCI FIFO */
v->pci.fifo.base = v->pci.fifo_mem;
v->pci.fifo.size = 64*2;
v->pci.fifo.in = v->pci.fifo.out = 0;
/* create a table of precomputed 1/n and log2(n) values */
/* n ranges from 1.0000 to 2.0000 */
for (val = 0; val <= (1 << RECIPLOG_LOOKUP_BITS); val++) {