This commit is contained in:
espes 2016-12-28 16:57:15 +01:00
parent c006d5e878
commit 45ed3c31b4
2 changed files with 417 additions and 243 deletions

View File

@ -450,19 +450,19 @@ typedef struct PGRAPHState {
ImageBlitState image_blit; ImageBlitState image_blit;
KelvinState kelvin; KelvinState kelvin;
unsigned int trapped_method; //NV_PGRAPH_TRAPPED_ADDR_MTHD // unsigned int trapped_method; //NV_PGRAPH_TRAPPED_ADDR_MTHD
unsigned int trapped_subchannel; //NV_PGRAPH_TRAPPED_ADDR_SUBCH // unsigned int trapped_subchannel; //NV_PGRAPH_TRAPPED_ADDR_SUBCH
unsigned int trapped_channel_id; //NV_PGRAPH_TRAPPED_ADDR_CHID // unsigned int trapped_channel_id; //NV_PGRAPH_TRAPPED_ADDR_CHID
uint32_t trapped_data[2]; //[0] = NV_PGRAPH_TRAPPED_DATA_LOW, [1] = NV_PGRAPH_TRAPPED_DATA_HIGH // uint32_t trapped_data[2]; //[0] = NV_PGRAPH_TRAPPED_DATA_LOW, [1] = NV_PGRAPH_TRAPPED_DATA_HIGH
uint32_t notify_source; //NV_PGRAPH_NSOURCE // uint32_t notify_source; //NV_PGRAPH_NSOURCE
bool fifo_access; //NV_PGRAPH_FIFO_ACCESS // bool fifo_access; //NV_PGRAPH_FIFO_ACCESS
QemuCond fifo_access_cond; QemuCond fifo_access_cond;
QemuCond flip_3d; QemuCond flip_3d;
unsigned int channel_id; //qqq NV_PGRAPH_CTX_USER_CHID, NV_PGRAPH_STATE3D_CHANNEL_ID? // unsigned int channel_id; //qqq NV_PGRAPH_CTX_USER_CHID, NV_PGRAPH_STATE3D_CHANNEL_ID?
bool channel_valid; //qqq NV_PGRAPH_CTX_CONTROL_CHID_VALID // bool channel_valid; //qqq NV_PGRAPH_CTX_CONTROL_CHID_VALID
// GraphicsContext context[NV2A_NUM_CHANNELS]; // GraphicsContext context[NV2A_NUM_CHANNELS];
hwaddr dma_color, dma_zeta; hwaddr dma_color, dma_zeta;
@ -487,7 +487,8 @@ typedef struct PGRAPHState {
GloContext *gl_context; GloContext *gl_context;
GLuint gl_framebuffer; GLuint gl_framebuffer;
GLuint gl_color_buffer, gl_zeta_buffer; GLuint gl_color_buffer, gl_zeta_buffer;
GraphicsSubchannel subchannel_data[NV2A_NUM_SUBCHANNELS]; // GraphicsSubchannel subchannel_data[NV2A_NUM_SUBCHANNELS];
// ??? NV_PFIFO_CACHE1_SUBCH_01_INST
hwaddr dma_report; hwaddr dma_report;
hwaddr report_offset; hwaddr report_offset;
@ -556,7 +557,7 @@ typedef struct PGRAPHState {
// uint32_t parameter; // uint32_t parameter;
// } CacheEntry; // } CacheEntry;
typedef struct Cache1State { // typedef struct Cache1State {
#if 0 #if 0
unsigned int channel_id; unsigned int channel_id;
enum FifoMode mode; enum FifoMode mode;
@ -572,7 +573,7 @@ typedef struct Cache1State {
unsigned int subchannel : 3; unsigned int subchannel : 3;
unsigned int method_count : 24; unsigned int method_count : 24;
uint32_t dcount; uint32_t dcount;
bool subroutine_active; bool subroutine_active; //NV_PFIFO_CACHE1_DMA_SUBROUTINE_STATE
hwaddr subroutine_return; hwaddr subroutine_return;
hwaddr get_jmp_shadow; hwaddr get_jmp_shadow;
uint32_t rsvd_shadow; uint32_t rsvd_shadow;
@ -585,15 +586,11 @@ typedef struct Cache1State {
#endif #endif
/* The actual command queue */ /* The actual command queue */
QemuMutex puller_lock;
QemuCond puller_cond;
QemuMutex pusher_lock;
QemuMutex pusher_cond;
// QemuMutex cache_lock; // QemuMutex cache_lock;
// QemuCond cache_cond; // QemuCond cache_cond;
// QSIMPLEQ_HEAD(, CacheEntry) cache; // QSIMPLEQ_HEAD(, CacheEntry) cache;
// QSIMPLEQ_HEAD(, CacheEntry) working_cache; // QSIMPLEQ_HEAD(, CacheEntry) working_cache;
} Cache1State; // } Cache1State;
// typedef struct ChannelControl { // typedef struct ChannelControl {
// hwaddr dma_put; // hwaddr dma_put;
@ -633,8 +630,13 @@ typedef struct NV2AState {
uint32_t pending_interrupts; uint32_t pending_interrupts;
uint32_t enabled_interrupts; uint32_t enabled_interrupts;
QemuMutex lock;
QemuThread puller_thread; QemuThread puller_thread;
Cache1State cache1; QemuCond puller_cond;
QemuThread pusher_thread;
QemuCond pusher_cond;
// Cache1State cache1;
uint32_t regs[0x2000]; uint32_t regs[0x2000];
} pfifo; } pfifo;
@ -674,7 +676,7 @@ typedef struct NV2AState {
} pramdac; } pramdac;
struct { struct {
ChannelControl channel_control[NV2A_NUM_CHANNELS]; // ChannelControl channel_control[NV2A_NUM_CHANNELS];
} user; } user;
} NV2AState; } NV2AState;
@ -784,7 +786,10 @@ static uint32_t ramht_hash(NV2AState *d, uint32_t handle)
hash ^= (handle & ((1 << bits) - 1)); hash ^= (handle & ((1 << bits) - 1));
handle >>= bits; handle >>= bits;
} }
hash ^= d->pfifo.cache1.channel_id << (bits - 4);
unsigned int channel_id = GET_MASK(d->pfifo.regs[NV_PFIFO_CACHE1_PUSH1],
NV_PFIFO_CACHE1_PUSH1_CHID);
hash ^= channel_id << (bits - 4);
return hash; return hash;
} }
@ -2726,11 +2731,13 @@ static void pgraph_method(NV2AState *d,
PGRAPHState *pg = &d->pgraph; PGRAPHState *pg = &d->pgraph;
assert(pg->channel_valid); bool channel_valid =
d->pgraph.regs[NV_PGRAPH_CTX_CONTROL] & NV_PGRAPH_CTX_CONTROL_CHID;
assert(channel_valid);
ContextSurfaces2DState *context_surfaces_2d = &pgraph->context_surfaces_2d; ContextSurfaces2DState *context_surfaces_2d = &pg->context_surfaces_2d;
ImageBlitState *image_blit = &pgraph->data.image_blit; ImageBlitState *image_blit = &pg->image_blit;
KelvinState *kelvin = &pgraph->data.kelvin; KelvinState *kelvin = &pg->kelvin;
if (method == NV_SET_OBJECT) { if (method == NV_SET_OBJECT) {
assert(parameter < memory_region_size(&d->ramin)); assert(parameter < memory_region_size(&d->ramin));
@ -2742,21 +2749,21 @@ static void pgraph_method(NV2AState *d,
uint32_t ctx_4 = ldl_le_p((uint32_t*)(obj_ptr+12)); uint32_t ctx_4 = ldl_le_p((uint32_t*)(obj_ptr+12));
uint32_t ctx_5 = parameter; uint32_t ctx_5 = parameter;
pgraph->regs[NV_PGRAPH_CTX_SWITCH1] = ctx_1; pg->regs[NV_PGRAPH_CTX_SWITCH1] = ctx_1;
pgraph->regs[NV_PGRAPH_CTX_SWITCH2] = ctx_2; pg->regs[NV_PGRAPH_CTX_SWITCH2] = ctx_2;
pgraph->regs[NV_PGRAPH_CTX_SWITCH3] = ctx_3; pg->regs[NV_PGRAPH_CTX_SWITCH3] = ctx_3;
pgraph->regs[NV_PGRAPH_CTX_SWITCH4] = ctx_4; pg->regs[NV_PGRAPH_CTX_SWITCH4] = ctx_4;
pgraph->regs[NV_PGRAPH_CTX_SWITCH5] = ctx_5; pg->regs[NV_PGRAPH_CTX_SWITCH5] = ctx_5;
assert(subchannel < 8); assert(subchannel < 8);
pgraph->regs[NV_PGRAPH_CTX_CACHE1 + subchannel * 4] = ctx_1; pg->regs[NV_PGRAPH_CTX_CACHE1 + subchannel * 4] = ctx_1;
pgraph->regs[NV_PGRAPH_CTX_CACHE2 + subchannel * 4] = ctx_2; pg->regs[NV_PGRAPH_CTX_CACHE2 + subchannel * 4] = ctx_2;
pgraph->regs[NV_PGRAPH_CTX_CACHE3 + subchannel * 4] = ctx_3; pg->regs[NV_PGRAPH_CTX_CACHE3 + subchannel * 4] = ctx_3;
pgraph->regs[NV_PGRAPH_CTX_CACHE4 + subchannel * 4] = ctx_4; pg->regs[NV_PGRAPH_CTX_CACHE4 + subchannel * 4] = ctx_4;
pgraph->regs[NV_PGRAPH_CTX_CACHE5 + subchannel * 4] = ctx_5; pg->regs[NV_PGRAPH_CTX_CACHE5 + subchannel * 4] = ctx_5;
} }
uint32_t graphics_class = GET_MASK(pgraph->regs[NV_PGRAPH_CTX_SWITCH1], uint32_t graphics_class = GET_MASK(pg->regs[NV_PGRAPH_CTX_SWITCH1],
NV_PGRAPH_CTX_SWITCH1_GRCLASS); NV_PGRAPH_CTX_SWITCH1_GRCLASS);
pgraph_method_log(subchannel, graphics_class, method, parameter); pgraph_method_log(subchannel, graphics_class, method, parameter);
@ -4798,15 +4805,20 @@ static void pgraph_method(NV2AState *d,
static void pgraph_context_switch(NV2AState *d, unsigned int channel_id) static void pgraph_context_switch(NV2AState *d, unsigned int channel_id)
{ {
bool valid; bool valid;
valid = d->pgraph.channel_valid && d->pgraph.channel_id == channel_id;
bool channel_valid =
d->pgraph.regs[NV_PGRAPH_CTX_CONTROL] & NV_PGRAPH_CTX_CONTROL_CHID;
valid = channel_valid && d->pgraph.channel_id == channel_id;
if (!valid) { if (!valid) {
d->pgraph.trapped_channel_id = channel_id; d->pgraph.trapped_channel_id = channel_id;
} }
if (!valid) { if (!valid) {
NV2A_DPRINTF("puller needs to switch to ch %d\n", channel_id); NV2A_DPRINTF("pgraph switching to ch %d\n", channel_id);
///qqq note bi NV_PGRAPH_DEBUG_3_HW_CONTEXT_SWITCH
/* TODO: hardware context switching */
assert(!(d->pgraph.regs[NV_PGRAPH_DEBUG_3]
& NV_PGRAPH_DEBUG_3_HW_CONTEXT_SWITCH));
qemu_mutex_unlock(&d->pgraph.lock); qemu_mutex_unlock(&d->pgraph.lock);
qemu_mutex_lock_iothread(); qemu_mutex_lock_iothread();
@ -4828,14 +4840,67 @@ static void pgraph_wait_fifo_access(NV2AState *d) {
} }
} }
static bool pfifo_run_puller(NV2AState *d)
{
uint32_t *pull0 = &d->pfifo.regs[NV_PFIFO_CACHE1_PULL0];
uint32_t *status = &d->pfifo.regs[NV_PFIFO_CACHE1_STATUS];
if (!GET_MASK(*pull0, NV_PFIFO_CACHE1_PULL0_ACCESS)) return;
CacheEntry working_cache[NV2A_CACHE1_SIZE];
int working_cache_size = 0;
// pull everything into our own queue
while (true) {
/* empty cache1 */
if (GET_MASK(*status, NV_PFIFO_CACHE1_STATUS_LOW_MARK)) return;
}
qemu_cond_signal(&d->pfifo.pusher_cond);
qemu_mutex_lock(&d->pgraph.lock);
//make pgraph busy
qemu_mutex_unlock(&d->pfifo.lock);
// process working_cache
// make pgraph not busy
qemu_mutex_unlock(&d->pgraph.lock);
qemu_mutex_lock(&d->pfifo.lock);
}
static void* pfifo_puller_thread(void *arg) static void* pfifo_puller_thread(void *arg)
{ {
NV2AState *d = arg; NV2AState *d = arg;
Cache1State *state = &d->pfifo.cache1; // Cache1State *state = &d->pfifo.cache1;
glo_set_current(d->pgraph.gl_context); glo_set_current(d->pgraph.gl_context);
// wait on CACHE1_PULL0_ACCESS
qemu_mutex_lock(&d->pfifo.lock);
while (true) {
pfifo_run_puller(d);
qemu_cond_wait(&d->pfifo.puller_cond, &d->pfifo.lock);
if (d->exiting) {
break;
}
}
qemu_mutex_unlock(&d->pfifo.lock);
// wait on CACHE1_PULL0_ACCESS - puller access to cache1
// while (true) { // while (true) {
@ -4928,14 +4993,8 @@ static void* pfifo_puller_thread(void *arg)
return NULL; return NULL;
} }
static void* pfifo_pusher_thread(void *arg) static void pfifo_run_pusher(NV2AState *d)
{ {
NV2AState *d = arg;
Cache1State *state = &d->pfifo.cache1;
/* TODO: How is cache1 selected? */
Cache1State *state = &d->pfifo.cache1;
uint32_t *push0 = &d->pfifo.regs[NV_PFIFO_CACHE1_PUSH0]; uint32_t *push0 = &d->pfifo.regs[NV_PFIFO_CACHE1_PUSH0];
uint32_t *push1 = &d->pfifo.regs[NV_PFIFO_CACHE1_PUSH1]; uint32_t *push1 = &d->pfifo.regs[NV_PFIFO_CACHE1_PUSH1];
uint32_t *dma_subroutine = &d->pfifo.regs[NV_PFIFO_CACHE1_DMA_SUBROUTINE]; uint32_t *dma_subroutine = &d->pfifo.regs[NV_PFIFO_CACHE1_DMA_SUBROUTINE];
@ -4944,33 +5003,28 @@ static void* pfifo_pusher_thread(void *arg)
uint32_t *dma_get = &d->pfifo.regs[NV_PFIFO_CACHE1_DMA_GET]; uint32_t *dma_get = &d->pfifo.regs[NV_PFIFO_CACHE1_DMA_GET];
uint32_t *dma_put = &d->pfifo.regs[NV_PFIFO_CACHE1_DMA_PUT]; uint32_t *dma_put = &d->pfifo.regs[NV_PFIFO_CACHE1_DMA_PUT];
uint32_t *dma_dcount = &d->pfifo.regs[NV_PFIFO_CACHE1_DMA_DCOUNT]; uint32_t *dma_dcount = &d->pfifo.regs[NV_PFIFO_CACHE1_DMA_DCOUNT];
uint32_t *status = &d->pfifo.regs[NV_PFIFO_CACHE1_STATUS];
uint32_t *get = &d->pfifo.regs[NV_PFIFO_CACHE1_GET]; uint32_t *get = &d->pfifo.regs[NV_PFIFO_CACHE1_GET];
uint32_t *put = &d->pfifo.regs[NV_PFIFO_CACHE1_PUT]; uint32_t *put = &d->pfifo.regs[NV_PFIFO_CACHE1_PUT];
while (true) { if (!GET_MASK(*push0, NV_PFIFO_CACHE1_PUSH0_ACCESS)) return;
qemu_mutex_lock(&state->pusher_lock); if (!GET_MASK(*dma_push, NV_PFIFO_CACHE1_DMA_PUSH_ACCESS)) return;
while (!GET_MASK(*push0, NV_PFIFO_CACHE1_PUSH0_ACCESS)
|| !GET_MASK(*dma_push, NV_PFIFO_CACHE1_DMA_PUSH_ACCESS)
|| GET_MASK(*dma_push, NV_PFIFO_CACHE1_DMA_PUSH_STATUS) /* suspended */
) {
qemu_cond_wait(&state->pusher_cond, &state->pusher_lock);
if (d->exiting) { /* suspended */
qemu_mutex_unlock(&state->pusher_lock); if (GET_MASK(*dma_push, NV_PFIFO_CACHE1_DMA_PUSH_STATUS)) return;
glo_set_current(NULL);
return NULL;
}
}
/* not handling PIO for now... */ // PPP should we become busy here??
// NV_PFIFO_CACHE1_DMA_PUSH_STATE _BUSY
unsigned int channel_id = GET_MASK(*push1, unsigned int channel_id = GET_MASK(*push1,
NV_PFIFO_CACHE1_PUSH1_CHID); NV_PFIFO_CACHE1_PUSH1_CHID);
/* Channel running DMA */ /* Channel running DMA mode */
uint32_t channel_modes = d->pfifo.regs[NV_PFIFO_MODE]; uint32_t channel_modes = d->pfifo.regs[NV_PFIFO_MODE];
assert(channel_modes & (1 << channel_id)); assert(channel_modes & (1 << channel_id));
assert(GET_MASK(*push1, NV_PFIFO_CACHE1_PUSH1_MODE) assert(GET_MASK(*push1, NV_PFIFO_CACHE1_PUSH1_MODE)
== NV_PFIFO_CACHE1_PUSH1_MODE_DMA); == NV_PFIFO_CACHE1_PUSH1_MODE_DMA);
@ -5010,14 +5064,24 @@ static void* pfifo_pusher_thread(void *arg)
GET_MASK(*dma_subroutine, NV_PFIFO_CACHE1_DMA_SUBROUTINE_STATE); GET_MASK(*dma_subroutine, NV_PFIFO_CACHE1_DMA_SUBROUTINE_STATE);
if (method_count) { if (method_count) {
/* full */
if (GET_MASK(*status, NV_PFIFO_CACHE1_STATUS_HIGH_MARK)) return;
/* data word of methods command */ /* data word of methods command */
d->pfifo.regs[NV_PFIFO_CACHE1_DMA_DATA_SHADOW] = word; d->pfifo.regs[NV_PFIFO_CACHE1_DMA_DATA_SHADOW] = word;
/////////////// ///////////////
// PPP actually do push...
///////////////
// set high mark if full
qemu_cond_signal(&d->pfifo.puller_cond);
if (method_type == NV_PFIFO_CACHE1_DMA_STATE_METHOD_TYPE_INC) { if (method_type == NV_PFIFO_CACHE1_DMA_STATE_METHOD_TYPE_INC) {
SET_MASK(*dma_sate, NV_PFIFO_CACHE1_DMA_STATE_METHOD, SET_MASK(*dma_state, NV_PFIFO_CACHE1_DMA_STATE_METHOD,
method + 4); method + 4);
} }
SET_MASK(*dma_state, NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT, SET_MASK(*dma_state, NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT,
@ -5042,30 +5106,34 @@ static void* pfifo_pusher_thread(void *arg)
NV2A_DPRINTF("pb JMP 0x%" HWADDR_PRIx "\n", dma_get_v); NV2A_DPRINTF("pb JMP 0x%" HWADDR_PRIx "\n", dma_get_v);
} else if ((word & 3) == 2) { } else if ((word & 3) == 2) {
/* call */ /* call */
if (state->subroutine_active) { if (subroutine_active) {
state->error = NV_PFIFO_CACHE1_DMA_STATE_ERROR_CALL; SET_MASK(*dma_state, NV_PFIFO_CACHE1_DMA_STATE_ERROR,
NV_PFIFO_CACHE1_DMA_STATE_ERROR_CALL);
break; break;
} } else {
state->subroutine_return = control->dma_get; *dma_subroutine = dma_get_v;
state->subroutine_active = true; SET_MASK(*dma_subroutine,
control->dma_get = word & 0xfffffffc; NV_PFIFO_CACHE1_DMA_SUBROUTINE_STATE, 1);
dma_get_v = word & 0xfffffffc;
NV2A_DPRINTF("pb CALL 0x%" HWADDR_PRIx "\n", dma_get_v); NV2A_DPRINTF("pb CALL 0x%" HWADDR_PRIx "\n", dma_get_v);
}
} else if (word == 0x00020000) { } else if (word == 0x00020000) {
/* return */ /* return */
if (!subroutine_state) { if (!subroutine_state) {
SET_MASK(*dma_state, NV_PFIFO_CACHE1_DMA_STATE_ERROR, SET_MASK(*dma_state, NV_PFIFO_CACHE1_DMA_STATE_ERROR,
NV_PFIFO_CACHE1_DMA_STATE_ERROR_RETURN); NV_PFIFO_CACHE1_DMA_STATE_ERROR_RETURN);
break; // break;
} } else {
dma_get_v = state->subroutine_return; dma_get_v = *dma_subroutine & 0xfffffffc;
SET_MASK(*dma_subroutine, NV_PFIFO_CACHE1_DMA_SUBROUTINE_STATE, SET_MASK(*dma_subroutine,
0); NV_PFIFO_CACHE1_DMA_SUBROUTINE_STATE, 0);
NV2A_DPRINTF("pb RET 0x%" HWADDR_PRIx "\n", dma_get_v); NV2A_DPRINTF("pb RET 0x%" HWADDR_PRIx "\n", dma_get_v);
}
} else if ((word & 0xe0030003) == 0) { } else if ((word & 0xe0030003) == 0) {
/* increasing methods */ /* increasing methods */
SET_MASK(*dma_state, NV_PFIFO_CACHE1_DMA_STATE_METHOD, SET_MASK(*dma_state, NV_PFIFO_CACHE1_DMA_STATE_METHOD,
word & 0x1fff); word & 0x1fff);
SET_MASK(*dma_sate, NV_PFIFO_CACHE1_DMA_STATE_SUBCHANNEL, SET_MASK(*dma_state, NV_PFIFO_CACHE1_DMA_STATE_SUBCHANNEL,
(word >> 13) & 7); (word >> 13) & 7);
SET_MASK(*dma_state, NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT, SET_MASK(*dma_state, NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT,
(word >> 18) & 0x7ff); (word >> 18) & 0x7ff);
@ -5076,7 +5144,7 @@ static void* pfifo_pusher_thread(void *arg)
/* non-increasing methods */ /* non-increasing methods */
SET_MASK(*dma_state, NV_PFIFO_CACHE1_DMA_STATE_METHOD, SET_MASK(*dma_state, NV_PFIFO_CACHE1_DMA_STATE_METHOD,
word & 0x1fff); word & 0x1fff);
SET_MASK(*dma_sate, NV_PFIFO_CACHE1_DMA_STATE_SUBCHANNEL, SET_MASK(*dma_state, NV_PFIFO_CACHE1_DMA_STATE_SUBCHANNEL,
(word >> 13) & 7); (word >> 13) & 7);
SET_MASK(*dma_state, NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT, SET_MASK(*dma_state, NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT,
(word >> 18) & 0x7ff); (word >> 18) & 0x7ff);
@ -5088,27 +5156,81 @@ static void* pfifo_pusher_thread(void *arg)
control->dma_get, word); control->dma_get, word);
SET_MASK(*dma_state, NV_PFIFO_CACHE1_DMA_STATE_ERROR, SET_MASK(*dma_state, NV_PFIFO_CACHE1_DMA_STATE_ERROR,
NV_PFIFO_CACHE1_DMA_STATE_ERROR_RESERVED_CMD); NV_PFIFO_CACHE1_DMA_STATE_ERROR_RESERVED_CMD);
break; // break;
} }
} }
*dma_get = dma_get_v; *dma_get = dma_get_v;
if (error) {
break;
}
} }
// NV2A_DPRINTF("DMA pusher done: max 0x%" HWADDR_PRIx ", 0x%" HWADDR_PRIx " - 0x%" HWADDR_PRIx "\n", // NV2A_DPRINTF("DMA pusher done: max 0x%" HWADDR_PRIx ", 0x%" HWADDR_PRIx " - 0x%" HWADDR_PRIx "\n",
// dma_len, control->dma_get, control->dma_put); // dma_len, control->dma_get, control->dma_put);
uint32_t error = GET_MASK(*dma_state, NV_PFIFO_CACHE1_DMA_STATE_ERROR) uint32_t error = GET_MASK(*dma_state, NV_PFIFO_CACHE1_DMA_STATE_ERROR);
if (error) { if (error) {
NV2A_DPRINTF("pb error: %d\n", error); NV2A_DPRINTF("pb error: %d\n", error);
assert(false); assert(false);
SET_MASK(*dma_push, NV_PFIFO_CACHE1_DMA_PUSH_STATUS, 1); /* suspended */ SET_MASK(*dma_push, NV_PFIFO_CACHE1_DMA_PUSH_STATUS, 1); /* suspended */
d->pfifo.pending_interrupts |= NV_PFIFO_INTR_0_DMA_PUSHER; // d->pfifo.pending_interrupts |= NV_PFIFO_INTR_0_DMA_PUSHER;
update_irq(d); // update_irq(d);
}
}
static void* pfifo_pusher_thread(void *arg)
{
NV2AState *d = arg;
// Cache1State *state = &d->pfifo.cache1;
/* TODO: How is cache1 selected? */
// Cache1State *state = &d->pfifo.cache1;
qemu_mutex_lock(&d->pfifo.lock);
while (true) {
pfifo_run_pusher(d);
qemu_cond_wait(&d->pfifo.pusher_cond, &d->pfifo.lock);
if (d->exiting) {
break;
} }
} }
qemu_mutex_unlock(&d->pfifo.lock);
// uint32_t *push0 = &d->pfifo.regs[NV_PFIFO_CACHE1_PUSH0];
// uint32_t *push1 = &d->pfifo.regs[NV_PFIFO_CACHE1_PUSH1];
// uint32_t *dma_subroutine = &d->pfifo.regs[NV_PFIFO_CACHE1_DMA_SUBROUTINE];
// uint32_t *dma_state = &d->pfifo.regs[NV_PFIFO_CACHE1_DMA_STATE];
// uint32_t *dma_push = &d->pfifo.regs[NV_PFIFO_CACHE1_DMA_PUSH];
// uint32_t *dma_get = &d->pfifo.regs[NV_PFIFO_CACHE1_DMA_GET];
// uint32_t *dma_put = &d->pfifo.regs[NV_PFIFO_CACHE1_DMA_PUT];
// uint32_t *dma_dcount = &d->pfifo.regs[NV_PFIFO_CACHE1_DMA_DCOUNT];
// uint32_t *status = &d->pfifo.regs[NV_PFIFO_CACHE1_STATUS];
// uint32_t *get = &d->pfifo.regs[NV_PFIFO_CACHE1_GET];
// uint32_t *put = &d->pfifo.regs[NV_PFIFO_CACHE1_PUT];
// while (true) {
// qemu_mutex_lock(&state->pusher_lock);
// while (!GET_MASK(*push0, NV_PFIFO_CACHE1_PUSH0_ACCESS)
// || !GET_MASK(*dma_push, NV_PFIFO_CACHE1_DMA_PUSH_ACCESS)
// || GET_MASK(*dma_push, NV_PFIFO_CACHE1_DMA_PUSH_STATUS) /* suspended */
// ) {
// qemu_cond_wait(&state->pusher_cond, &state->pusher_lock);
// if (d->exiting) {
// qemu_mutex_unlock(&state->pusher_lock);
// glo_set_current(NULL);
// return NULL;
// }
// }
// }
#if 0 #if 0
NV2A_DPRINTF("DMA pusher: max 0x%" HWADDR_PRIx ", 0x%" HWADDR_PRIx " - 0x%" HWADDR_PRIx "\n", NV2A_DPRINTF("DMA pusher: max 0x%" HWADDR_PRIx ", 0x%" HWADDR_PRIx " - 0x%" HWADDR_PRIx "\n",
@ -5321,6 +5443,8 @@ static uint64_t pfifo_read(void *opaque,
int i; int i;
NV2AState *d = opaque; NV2AState *d = opaque;
qemu_mutex_lock(&d->pfifo.lock);
uint64_t r = 0; uint64_t r = 0;
switch (addr) { switch (addr) {
case NV_PFIFO_INTR_0: case NV_PFIFO_INTR_0:
@ -5408,6 +5532,8 @@ static uint64_t pfifo_read(void *opaque,
break; break;
} }
qemu_mutex_unlock(&d->pfifo.lock);
reg_log_read(NV_PFIFO, addr, r); reg_log_read(NV_PFIFO, addr, r);
return r; return r;
} }
@ -5855,9 +5981,9 @@ static void pgraph_write(void *opaque, hwaddr addr,
case NV_PGRAPH_INTR_EN: case NV_PGRAPH_INTR_EN:
d->pgraph.enabled_interrupts = val; d->pgraph.enabled_interrupts = val;
break; break;
case NV_PGRAPH_CTX_CONTROL: // case NV_PGRAPH_CTX_CONTROL:
d->pgraph.channel_valid = (val & NV_PGRAPH_CTX_CONTROL_CHID); // d->pgraph.channel_valid = (val & NV_PGRAPH_CTX_CONTROL_CHID);
break; // break;
// case NV_PGRAPH_CTX_USER: // case NV_PGRAPH_CTX_USER:
// pgraph_set_context_user(d, val); // pgraph_set_context_user(d, val);
// break; // break;
@ -6105,31 +6231,45 @@ static uint64_t user_read(void *opaque,
unsigned int channel_id = addr >> 16; unsigned int channel_id = addr >> 16;
assert(channel_id < NV2A_NUM_CHANNELS); assert(channel_id < NV2A_NUM_CHANNELS);
ChannelControl *control = &d->user.channel_control[channel_id]; qemu_mutex_lock(&d->pfifo.lock);
// ChannelControl *control = &d->user.channel_control[channel_id];
uint32_t channel_modes = d->pfifo.regs[NV_PFIFO_MODE]; uint32_t channel_modes = d->pfifo.regs[NV_PFIFO_MODE];
uint64_t r = 0; uint64_t r = 0;
if (channel_modes & (1 << channel_id)) { if (channel_modes & (1 << channel_id)) {
/* DMA Mode */ /* DMA Mode */
unsigned int cur_channel_id =
GET_MASK(d->pfifo.regs[NV_PFIFO_CACHE1_PUSH1],
NV_PFIFO_CACHE1_PUSH1_CHID);
if (channel_id == cur_channel_id) {
switch (addr & 0xFFFF) { switch (addr & 0xFFFF) {
case NV_USER_DMA_PUT: case NV_USER_DMA_PUT:
r = control->dma_put; r = d->pfifo.regs[NV_PFIFO_CACHE1_DMA_PUT];
break; break;
case NV_USER_DMA_GET: case NV_USER_DMA_GET:
r = control->dma_get; r = d->pfifo.regs[NV_PFIFO_CACHE1_DMA_GET];
break; break;
case NV_USER_REF: case NV_USER_REF:
r = control->ref; r = d->pfifo.regs[NV_PFIFO_CACHE1_REF];
break; break;
default: default:
break; break;
} }
} else {
/* ramfc */
assert(false);
}
} else { } else {
/* PIO Mode */ /* PIO Mode */
assert(false); assert(false);
} }
qemu_mutex_unlock(&d->pfifo.lock);
reg_log_read(NV_USER, addr, r); reg_log_read(NV_USER, addr, r);
return r; return r;
} }
@ -6143,33 +6283,60 @@ static void user_write(void *opaque, hwaddr addr,
unsigned int channel_id = addr >> 16; unsigned int channel_id = addr >> 16;
assert(channel_id < NV2A_NUM_CHANNELS); assert(channel_id < NV2A_NUM_CHANNELS);
ChannelControl *control = &d->user.channel_control[channel_id]; // ChannelControl *control = &d->user.channel_control[channel_id];
qemu_mutex_lock(&d->pfifo.lock);
uint32_t channel_modes = d->pfifo.regs[NV_PFIFO_MODE]; uint32_t channel_modes = d->pfifo.regs[NV_PFIFO_MODE];
if (channel_modes & (1 << channel_id)) { if (channel_modes & (1 << channel_id)) {
/* DMA Mode */ /* DMA Mode */
unsigned int cur_channel_id =
GET_MASK(d->pfifo.regs[NV_PFIFO_CACHE1_PUSH1],
NV_PFIFO_CACHE1_PUSH1_CHID);
if (channel_id == cur_channel_id) {
switch (addr & 0xFFFF) { switch (addr & 0xFFFF) {
case NV_USER_DMA_PUT: case NV_USER_DMA_PUT:
control->dma_put = val; d->pfifo.regs[NV_PFIFO_CACHE1_DMA_PUT] = val;
if (d->pfifo.cache1.push_enabled) {
pfifo_run_pusher(d);
}
break; break;
case NV_USER_DMA_GET: case NV_USER_DMA_GET:
control->dma_get = val; d->pfifo.regs[NV_PFIFO_CACHE1_DMA_GET] = val;
break; break;
case NV_USER_REF: case NV_USER_REF:
control->ref = val; d->pfifo.regs[NV_PFIFO_CACHE1_REF] = val;
break; break;
default: default:
break; break;
} }
} else {
/* ramfc */
assert(false);
}
// switch (addr & 0xFFFF) {
// case NV_USER_DMA_PUT:
// control->dma_put = val;
// if (d->pfifo.cache1.push_enabled) {
// pfifo_run_pusher(d);
// }
// break;
// case NV_USER_DMA_GET:
// control->dma_get = val;
// break;
// case NV_USER_REF:
// control->ref = val;
// break;
// default:
// break;
// }
} else { } else {
/* PIO Mode */ /* PIO Mode */
assert(false); assert(false);
} }
qemu_mutex_unlock(&d->pfifo.lock);
} }
@ -6650,10 +6817,11 @@ static int nv2a_initfn(PCIDevice *dev)
} }
/* init fifo cache1 */ /* init fifo cache1 */
qemu_mutex_init(&d->pfifo.cache1.cache_lock); //PPP
qemu_cond_init(&d->pfifo.cache1.cache_cond); // qemu_mutex_init(&d->pfifo.cache1.cache_lock);
QSIMPLEQ_INIT(&d->pfifo.cache1.cache); // qemu_cond_init(&d->pfifo.cache1.cache_cond);
QSIMPLEQ_INIT(&d->pfifo.cache1.working_cache); // QSIMPLEQ_INIT(&d->pfifo.cache1.cache);
// QSIMPLEQ_INIT(&d->pfifo.cache1.working_cache);
return 0; return 0;
} }
@ -6664,11 +6832,13 @@ static void nv2a_exitfn(PCIDevice *dev)
d = NV2A_DEVICE(dev); d = NV2A_DEVICE(dev);
d->exiting = true; d->exiting = true;
qemu_cond_signal(&d->pfifo.cache1.cache_cond);
qemu_thread_join(&d->pfifo.puller_thread);
qemu_mutex_destroy(&d->pfifo.cache1.cache_lock); //PPP
qemu_cond_destroy(&d->pfifo.cache1.cache_cond); // qemu_cond_signal(&d->pfifo.cache1.cache_cond);
// qemu_thread_join(&d->pfifo.puller_thread);
// qemu_mutex_destroy(&d->pfifo.cache1.cache_lock);
// qemu_cond_destroy(&d->pfifo.cache1.cache_cond);
pgraph_destroy(&d->pgraph); pgraph_destroy(&d->pgraph);
} }

View File

@ -146,6 +146,7 @@
# define NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS 0x0000FFFF # define NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS 0x0000FFFF
#define NV_PFIFO_CACHE1_DMA_PUT 0x00001240 #define NV_PFIFO_CACHE1_DMA_PUT 0x00001240
#define NV_PFIFO_CACHE1_DMA_GET 0x00001244 #define NV_PFIFO_CACHE1_DMA_GET 0x00001244
#define NV_PFIFO_CACHE1_REF 0x00001248
#define NV_PFIFO_CACHE1_DMA_SUBROUTINE 0x0000124C #define NV_PFIFO_CACHE1_DMA_SUBROUTINE 0x0000124C
# define NV_PFIFO_CACHE1_DMA_SUBROUTINE_RETURN_OFFSET 0x1FFFFFFC # define NV_PFIFO_CACHE1_DMA_SUBROUTINE_RETURN_OFFSET 0x1FFFFFFC
# define NV_PFIFO_CACHE1_DMA_SUBROUTINE_STATE (1 << 0) # define NV_PFIFO_CACHE1_DMA_SUBROUTINE_STATE (1 << 0)
@ -162,6 +163,8 @@
#define NV_PFIFO_CACHE1_METHOD 0x00001800 #define NV_PFIFO_CACHE1_METHOD 0x00001800
#define NV_PFIFO_CACHE1_DATA 0x00001804 #define NV_PFIFO_CACHE1_DATA 0x00001804
#define NV_PGRAPH_DEBUG_3 0x0000008C
# define NV_PGRAPH_DEBUG_3_HW_CONTEXT_SWITCH (1 << 2)
#define NV_PGRAPH_INTR 0x00000100 #define NV_PGRAPH_INTR 0x00000100
# define NV_PGRAPH_INTR_NOTIFY (1 << 0) # define NV_PGRAPH_INTR_NOTIFY (1 << 0)
# define NV_PGRAPH_INTR_MISSING_HW (1 << 4) # define NV_PGRAPH_INTR_MISSING_HW (1 << 4)
@ -1259,6 +1262,7 @@
#define NV2A_CRYSTAL_FREQ 13500000 #define NV2A_CRYSTAL_FREQ 13500000
#define NV2A_NUM_CHANNELS 32 #define NV2A_NUM_CHANNELS 32
#define NV2A_NUM_SUBCHANNELS 8 #define NV2A_NUM_SUBCHANNELS 8
#define NV2A_CACHE1_SIZE 128
#define NV2A_MAX_BATCH_LENGTH 0x1FFFF #define NV2A_MAX_BATCH_LENGTH 0x1FFFF
#define NV2A_VERTEXSHADER_ATTRIBUTES 16 #define NV2A_VERTEXSHADER_ATTRIBUTES 16