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:
parent
ea8bfca53f
commit
1f85292418
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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++) {
|
||||
|
Loading…
Reference in New Issue
Block a user