Big refactoring, reintroducing state-arguments, moving lots of code from old to OpenXbox-comparable locations, all the while keeping it all compiling
This commit is contained in:
parent
998e68b681
commit
1bf01df4b7
File diff suppressed because it is too large
Load Diff
|
@ -37,20 +37,6 @@
|
|||
// Valid after PCI init :
|
||||
#define NV20_REG_BASE_KERNEL 0xFD000000
|
||||
|
||||
#define NV2A_ADDR 0xFD000000
|
||||
#define NV2A_SIZE 0x01000000
|
||||
|
||||
#define NV_PMC_SIZE 0x001000
|
||||
#define _NV_PFIFO_SIZE 0x002000 // Underscore prefix to prevent clash with NV_PFIFO_SIZE
|
||||
#define NV_PVIDEO_SIZE 0x001000
|
||||
#define NV_PTIMER_SIZE 0x001000
|
||||
#define NV_PFB_SIZE 0x001000
|
||||
#define NV_PGRAPH_SIZE 0x002000
|
||||
#define NV_PCRTC_SIZE 0x001000
|
||||
#define NV_PRAMDAC_SIZE 0x001000
|
||||
#define NV_PRAMIN_ADDR 0x00700000
|
||||
#define NV_PRAMIN_SIZE 0x100000
|
||||
|
||||
typedef volatile DWORD *PPUSH;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -3,13 +3,13 @@ DEVICE_READ32(PCRTC)
|
|||
DEVICE_READ32_SWITCH() {
|
||||
|
||||
case NV_PCRTC_INTR_0:
|
||||
result = pcrtc.pending_interrupts;
|
||||
result = d->pcrtc.pending_interrupts;
|
||||
break;
|
||||
case NV_PCRTC_INTR_EN_0:
|
||||
result = pcrtc.enabled_interrupts;
|
||||
result = d->pcrtc.enabled_interrupts;
|
||||
break;
|
||||
case NV_PCRTC_START:
|
||||
result = pcrtc.start;
|
||||
result = d->pcrtc.start;
|
||||
break;
|
||||
default:
|
||||
result = 0;
|
||||
|
@ -25,17 +25,17 @@ DEVICE_WRITE32(PCRTC)
|
|||
switch (addr) {
|
||||
|
||||
case NV_PCRTC_INTR_0:
|
||||
pcrtc.pending_interrupts &= ~value;
|
||||
update_irq();
|
||||
d->pcrtc.pending_interrupts &= ~value;
|
||||
update_irq(d);
|
||||
break;
|
||||
case NV_PCRTC_INTR_EN_0:
|
||||
pcrtc.enabled_interrupts = value;
|
||||
update_irq();
|
||||
d->pcrtc.enabled_interrupts = value;
|
||||
update_irq(d);
|
||||
break;
|
||||
case NV_PCRTC_START:
|
||||
value &= 0x07FFFFFF;
|
||||
// assert(val < memory_region_size(d->vram));
|
||||
pcrtc.start = value;
|
||||
d->pcrtc.start = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -1,3 +1,15 @@
|
|||
typedef struct RAMHTEntry {
|
||||
uint32_t handle;
|
||||
xbaddr instance;
|
||||
enum FIFOEngine engine;
|
||||
unsigned int channel_id : 5;
|
||||
bool valid;
|
||||
} RAMHTEntry;
|
||||
|
||||
static void pfifo_run_pusher(NV2AState *d); // forward declaration
|
||||
int pfifo_puller_thread(void *opaque);
|
||||
static RAMHTEntry ramht_lookup(NV2AState *d, uint32_t handle); // forward declaration
|
||||
|
||||
DEVICE_READ32(PFIFO)
|
||||
{
|
||||
DEVICE_READ32_SWITCH() {
|
||||
|
@ -8,84 +20,84 @@ DEVICE_READ32(PFIFO)
|
|||
result = 0x00890110; // = ? | NV_PFIFO_RAMFC_SIZE_2K | ?
|
||||
break;
|
||||
case NV_PFIFO_INTR_0:
|
||||
result = pfifo.pending_interrupts;
|
||||
result = d->pfifo.pending_interrupts;
|
||||
break;
|
||||
case NV_PFIFO_INTR_EN_0:
|
||||
result = pfifo.enabled_interrupts;
|
||||
result = d->pfifo.enabled_interrupts;
|
||||
break;
|
||||
case NV_PFIFO_RUNOUT_STATUS:
|
||||
result = NV_PFIFO_RUNOUT_STATUS_LOW_MARK; /* low mark empty */
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_PUSH0:
|
||||
result = pfifo.cache1.push_enabled;
|
||||
result = d->pfifo.cache1.push_enabled;
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_PUSH1:
|
||||
SET_MASK(result, NV_PFIFO_CACHE1_PUSH1_CHID, pfifo.cache1.channel_id);
|
||||
SET_MASK(result, NV_PFIFO_CACHE1_PUSH1_MODE, pfifo.cache1.mode);
|
||||
SET_MASK(result, NV_PFIFO_CACHE1_PUSH1_CHID, d->pfifo.cache1.channel_id);
|
||||
SET_MASK(result, NV_PFIFO_CACHE1_PUSH1_MODE, d->pfifo.cache1.mode);
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_STATUS: {
|
||||
std::lock_guard<std::mutex> lk(pfifo.cache1.mutex);
|
||||
std::lock_guard<std::mutex> lk(d->pfifo.cache1.mutex);
|
||||
|
||||
if (pfifo.cache1.cache.empty()) {
|
||||
if (d->pfifo.cache1.cache.empty()) {
|
||||
result |= NV_PFIFO_CACHE1_STATUS_LOW_MARK; /* low mark empty */
|
||||
}
|
||||
|
||||
} break;
|
||||
case NV_PFIFO_CACHE1_DMA_PUSH:
|
||||
SET_MASK(result, NV_PFIFO_CACHE1_DMA_PUSH_ACCESS,
|
||||
pfifo.cache1.dma_push_enabled);
|
||||
d->pfifo.cache1.dma_push_enabled);
|
||||
SET_MASK(result, NV_PFIFO_CACHE1_DMA_PUSH_STATUS,
|
||||
pfifo.cache1.dma_push_suspended);
|
||||
d->pfifo.cache1.dma_push_suspended);
|
||||
SET_MASK(result, NV_PFIFO_CACHE1_DMA_PUSH_BUFFER, 1); /* buffer emoty */
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_STATE:
|
||||
SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_METHOD_TYPE,
|
||||
pfifo.cache1.method_nonincreasing);
|
||||
d->pfifo.cache1.method_nonincreasing);
|
||||
SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_METHOD,
|
||||
pfifo.cache1.method >> 2);
|
||||
d->pfifo.cache1.method >> 2);
|
||||
SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_SUBCHANNEL,
|
||||
pfifo.cache1.subchannel);
|
||||
d->pfifo.cache1.subchannel);
|
||||
SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT,
|
||||
pfifo.cache1.method_count);
|
||||
d->pfifo.cache1.method_count);
|
||||
SET_MASK(result, NV_PFIFO_CACHE1_DMA_STATE_ERROR,
|
||||
pfifo.cache1.error);
|
||||
d->pfifo.cache1.error);
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_INSTANCE:
|
||||
SET_MASK(result, NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS_MASK,
|
||||
pfifo.cache1.dma_instance >> 4);
|
||||
d->pfifo.cache1.dma_instance >> 4);
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_PUT:
|
||||
result = user.channel_control[pfifo.cache1.channel_id].dma_put;
|
||||
result = d->user.channel_control[d->pfifo.cache1.channel_id].dma_put;
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_GET:
|
||||
result = user.channel_control[pfifo.cache1.channel_id].dma_get;
|
||||
result = d->user.channel_control[d->pfifo.cache1.channel_id].dma_get;
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_SUBROUTINE:
|
||||
result = pfifo.cache1.subroutine_return
|
||||
| pfifo.cache1.subroutine_active;
|
||||
result = d->pfifo.cache1.subroutine_return
|
||||
| d->pfifo.cache1.subroutine_active;
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_PULL0: {
|
||||
std::lock_guard<std::mutex> lk(pfifo.cache1.mutex);
|
||||
result = pfifo.cache1.pull_enabled;
|
||||
std::lock_guard<std::mutex> lk(d->pfifo.cache1.mutex);
|
||||
result = d->pfifo.cache1.pull_enabled;
|
||||
} break;
|
||||
case NV_PFIFO_CACHE1_ENGINE: {
|
||||
std::lock_guard<std::mutex> lk(pfifo.cache1.mutex);
|
||||
std::lock_guard<std::mutex> lk(d->pfifo.cache1.mutex);
|
||||
for (int i = 0; i < NV2A_NUM_SUBCHANNELS; i++) {
|
||||
result |= pfifo.cache1.bound_engines[i] << (i * 2);
|
||||
result |= d->pfifo.cache1.bound_engines[i] << (i * 2);
|
||||
}
|
||||
|
||||
} break;
|
||||
case NV_PFIFO_CACHE1_DMA_DCOUNT:
|
||||
result = pfifo.cache1.dcount;
|
||||
result = d->pfifo.cache1.dcount;
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_GET_JMP_SHADOW:
|
||||
result = pfifo.cache1.get_jmp_shadow;
|
||||
result = d->pfifo.cache1.get_jmp_shadow;
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_RSVD_SHADOW:
|
||||
result = pfifo.cache1.rsvd_shadow;
|
||||
result = d->pfifo.cache1.rsvd_shadow;
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_DATA_SHADOW:
|
||||
result = pfifo.cache1.data_shadow;
|
||||
result = d->pfifo.cache1.data_shadow;
|
||||
break;
|
||||
default:
|
||||
DEVICE_READ32_REG(pfifo); // Was : DEBUG_READ32_UNHANDLED(PFIFO);
|
||||
|
@ -99,82 +111,82 @@ DEVICE_WRITE32(PFIFO)
|
|||
{
|
||||
switch(addr) {
|
||||
case NV_PFIFO_INTR_0:
|
||||
pfifo.pending_interrupts &= ~value;
|
||||
update_irq();
|
||||
d->pfifo.pending_interrupts &= ~value;
|
||||
update_irq(d);
|
||||
break;
|
||||
case NV_PFIFO_INTR_EN_0:
|
||||
pfifo.enabled_interrupts = value;
|
||||
update_irq();
|
||||
d->pfifo.enabled_interrupts = value;
|
||||
update_irq(d);
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_PUSH0:
|
||||
pfifo.cache1.push_enabled = value & NV_PFIFO_CACHE1_PUSH0_ACCESS;
|
||||
d->pfifo.cache1.push_enabled = value & NV_PFIFO_CACHE1_PUSH0_ACCESS;
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_PUSH1:
|
||||
pfifo.cache1.channel_id = GET_MASK(value, NV_PFIFO_CACHE1_PUSH1_CHID);
|
||||
pfifo.cache1.mode = (FifoMode)GET_MASK(value, NV_PFIFO_CACHE1_PUSH1_MODE);
|
||||
assert(pfifo.cache1.channel_id < NV2A_NUM_CHANNELS);
|
||||
d->pfifo.cache1.channel_id = GET_MASK(value, NV_PFIFO_CACHE1_PUSH1_CHID);
|
||||
d->pfifo.cache1.mode = (FifoMode)GET_MASK(value, NV_PFIFO_CACHE1_PUSH1_MODE);
|
||||
assert(d->pfifo.cache1.channel_id < NV2A_NUM_CHANNELS);
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_PUSH:
|
||||
pfifo.cache1.dma_push_enabled = GET_MASK(value, NV_PFIFO_CACHE1_DMA_PUSH_ACCESS);
|
||||
if (pfifo.cache1.dma_push_suspended && !GET_MASK(value, NV_PFIFO_CACHE1_DMA_PUSH_STATUS)) {
|
||||
pfifo.cache1.dma_push_suspended = false;
|
||||
pfifo_run_pusher();
|
||||
d->pfifo.cache1.dma_push_enabled = GET_MASK(value, NV_PFIFO_CACHE1_DMA_PUSH_ACCESS);
|
||||
if (d->pfifo.cache1.dma_push_suspended && !GET_MASK(value, NV_PFIFO_CACHE1_DMA_PUSH_STATUS)) {
|
||||
d->pfifo.cache1.dma_push_suspended = false;
|
||||
pfifo_run_pusher(d);
|
||||
}
|
||||
pfifo.cache1.dma_push_suspended = GET_MASK(value, NV_PFIFO_CACHE1_DMA_PUSH_STATUS);
|
||||
d->pfifo.cache1.dma_push_suspended = GET_MASK(value, NV_PFIFO_CACHE1_DMA_PUSH_STATUS);
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_STATE:
|
||||
pfifo.cache1.method_nonincreasing = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_METHOD_TYPE);
|
||||
pfifo.cache1.method = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_METHOD) << 2;
|
||||
pfifo.cache1.subchannel = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_SUBCHANNEL);
|
||||
pfifo.cache1.method_count = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT);
|
||||
pfifo.cache1.error = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_ERROR);
|
||||
d->pfifo.cache1.method_nonincreasing = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_METHOD_TYPE);
|
||||
d->pfifo.cache1.method = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_METHOD) << 2;
|
||||
d->pfifo.cache1.subchannel = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_SUBCHANNEL);
|
||||
d->pfifo.cache1.method_count = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT);
|
||||
d->pfifo.cache1.error = GET_MASK(value, NV_PFIFO_CACHE1_DMA_STATE_ERROR);
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_INSTANCE:
|
||||
pfifo.cache1.dma_instance = GET_MASK(value, NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS_MASK) << 4;
|
||||
d->pfifo.cache1.dma_instance = GET_MASK(value, NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS_MASK) << 4;
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_PUT:
|
||||
user.channel_control[pfifo.cache1.channel_id].dma_put = value;
|
||||
d->user.channel_control[d->pfifo.cache1.channel_id].dma_put = value;
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_GET:
|
||||
user.channel_control[pfifo.cache1.channel_id].dma_get = value;
|
||||
d->user.channel_control[d->pfifo.cache1.channel_id].dma_get = value;
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_SUBROUTINE:
|
||||
pfifo.cache1.subroutine_return = (value & NV_PFIFO_CACHE1_DMA_SUBROUTINE_RETURN_OFFSET);
|
||||
pfifo.cache1.subroutine_active = (value & NV_PFIFO_CACHE1_DMA_SUBROUTINE_STATE);
|
||||
d->pfifo.cache1.subroutine_return = (value & NV_PFIFO_CACHE1_DMA_SUBROUTINE_RETURN_OFFSET);
|
||||
d->pfifo.cache1.subroutine_active = (value & NV_PFIFO_CACHE1_DMA_SUBROUTINE_STATE);
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_PULL0: {
|
||||
std::lock_guard<std::mutex> lk(pfifo.cache1.mutex);
|
||||
std::lock_guard<std::mutex> lk(d->pfifo.cache1.mutex);
|
||||
|
||||
if ((value & NV_PFIFO_CACHE1_PULL0_ACCESS)
|
||||
&& !pfifo.cache1.pull_enabled) {
|
||||
pfifo.cache1.pull_enabled = true;
|
||||
&& !d->pfifo.cache1.pull_enabled) {
|
||||
d->pfifo.cache1.pull_enabled = true;
|
||||
|
||||
/* the puller thread should wake up */
|
||||
pfifo.cache1.cache_cond.notify_all();
|
||||
d->pfifo.cache1.cache_cond.notify_all();
|
||||
} else if (!(value & NV_PFIFO_CACHE1_PULL0_ACCESS)
|
||||
&& pfifo.cache1.pull_enabled) {
|
||||
pfifo.cache1.pull_enabled = false;
|
||||
&& d->pfifo.cache1.pull_enabled) {
|
||||
d->pfifo.cache1.pull_enabled = false;
|
||||
}
|
||||
} break;
|
||||
case NV_PFIFO_CACHE1_ENGINE: {
|
||||
std::lock_guard<std::mutex> lk(pfifo.cache1.mutex);
|
||||
std::lock_guard<std::mutex> lk(d->pfifo.cache1.mutex);
|
||||
|
||||
for (int i = 0; i < NV2A_NUM_SUBCHANNELS; i++) {
|
||||
pfifo.cache1.bound_engines[i] = (FIFOEngine)((value >> (i * 2)) & 3);
|
||||
d->pfifo.cache1.bound_engines[i] = (FIFOEngine)((value >> (i * 2)) & 3);
|
||||
}
|
||||
|
||||
} break;
|
||||
case NV_PFIFO_CACHE1_DMA_DCOUNT:
|
||||
pfifo.cache1.dcount = (value & NV_PFIFO_CACHE1_DMA_DCOUNT_VALUE);
|
||||
d->pfifo.cache1.dcount = (value & NV_PFIFO_CACHE1_DMA_DCOUNT_VALUE);
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_GET_JMP_SHADOW:
|
||||
pfifo.cache1.get_jmp_shadow = (value & NV_PFIFO_CACHE1_DMA_GET_JMP_SHADOW_OFFSET);
|
||||
d->pfifo.cache1.get_jmp_shadow = (value & NV_PFIFO_CACHE1_DMA_GET_JMP_SHADOW_OFFSET);
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_RSVD_SHADOW:
|
||||
pfifo.cache1.rsvd_shadow = value;
|
||||
d->pfifo.cache1.rsvd_shadow = value;
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_DATA_SHADOW:
|
||||
pfifo.cache1.data_shadow = value;
|
||||
d->pfifo.cache1.data_shadow = value;
|
||||
break;
|
||||
default:
|
||||
DEVICE_WRITE32_REG(pfifo); // Was : DEBUG_WRITE32_UNHANDLED(PFIFO);
|
||||
|
@ -186,7 +198,7 @@ DEVICE_WRITE32(PFIFO)
|
|||
|
||||
/* pusher should be fine to run from a mimo handler
|
||||
* whenever's it's convenient */
|
||||
static void pfifo_run_pusher() {
|
||||
static void pfifo_run_pusher(NV2AState *d) {
|
||||
uint8_t channel_id;
|
||||
ChannelControl *control;
|
||||
Cache1State *state;
|
||||
|
@ -196,16 +208,16 @@ static void pfifo_run_pusher() {
|
|||
uint32_t word;
|
||||
|
||||
/* TODO: How is cache1 selected? */
|
||||
state = &pfifo.cache1;
|
||||
state = &d->pfifo.cache1;
|
||||
channel_id = state->channel_id;
|
||||
control = &user.channel_control[channel_id];
|
||||
control = &d->user.channel_control[channel_id];
|
||||
|
||||
if (!state->push_enabled) return;
|
||||
|
||||
/* only handling DMA for now... */
|
||||
|
||||
/* Channel running DMA */
|
||||
uint32_t channel_modes = pfifo.regs[NV_PFIFO_MODE];
|
||||
uint32_t channel_modes = d->pfifo.regs[NV_PFIFO_MODE];
|
||||
assert(channel_modes & (1 << channel_id));
|
||||
assert(state->mode == FIFO_DMA);
|
||||
|
||||
|
@ -215,7 +227,7 @@ static void pfifo_run_pusher() {
|
|||
/* We're running so there should be no pending errors... */
|
||||
assert(state->error == NV_PFIFO_CACHE1_DMA_STATE_ERROR_NONE);
|
||||
|
||||
dma = (uint8_t*)nv_dma_map(state->dma_instance, &dma_len);
|
||||
dma = (uint8_t*)nv_dma_map(d, state->dma_instance, &dma_len);
|
||||
|
||||
printf("DMA pusher: max 0x%08X, 0x%08X - 0x%08X\n",
|
||||
dma_len, control->dma_get, control->dma_put);
|
||||
|
@ -321,14 +333,17 @@ static void pfifo_run_pusher() {
|
|||
|
||||
state->dma_push_suspended = true;
|
||||
|
||||
pfifo.pending_interrupts |= NV_PFIFO_INTR_0_DMA_PUSHER;
|
||||
update_irq();
|
||||
d->pfifo.pending_interrupts |= NV_PFIFO_INTR_0_DMA_PUSHER;
|
||||
update_irq(d);
|
||||
}
|
||||
}
|
||||
|
||||
static void* pfifo_puller_thread()
|
||||
int pfifo_puller_thread(void *opaque)
|
||||
{
|
||||
Cache1State *state = &pfifo.cache1;
|
||||
CxbxSetThreadName("Cxbx NV2A FIFO");
|
||||
|
||||
NV2AState *d = (NV2AState *)opaque;
|
||||
Cache1State *state = &d->pfifo.cache1;
|
||||
|
||||
while (true) {
|
||||
// Scope the lock so that it automatically unlocks at tne end of this block
|
||||
|
@ -352,7 +367,7 @@ static void* pfifo_puller_thread()
|
|||
|
||||
if (command->method == 0) {
|
||||
// qemu_mutex_lock_iothread();
|
||||
RAMHTEntry entry = ramht_lookup(command->parameter);
|
||||
RAMHTEntry entry = ramht_lookup(d, command->parameter);
|
||||
assert(entry.valid);
|
||||
|
||||
assert(entry.channel_id == state->channel_id);
|
||||
|
@ -360,9 +375,9 @@ static void* pfifo_puller_thread()
|
|||
|
||||
switch (entry.engine) {
|
||||
case ENGINE_GRAPHICS:
|
||||
pgraph_context_switch(entry.channel_id);
|
||||
pgraph_wait_fifo_access();
|
||||
pgraph_method(command->subchannel, 0, entry.instance);
|
||||
pgraph_context_switch(d, entry.channel_id);
|
||||
pgraph_wait_fifo_access(d);
|
||||
pgraph_method(d, command->subchannel, 0, entry.instance);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
|
@ -370,7 +385,7 @@ static void* pfifo_puller_thread()
|
|||
}
|
||||
|
||||
/* the engine is bound to the subchannel */
|
||||
std::lock_guard<std::mutex> lk(pfifo.cache1.mutex);
|
||||
std::lock_guard<std::mutex> lk(state->mutex);
|
||||
state->bound_engines[command->subchannel] = entry.engine;
|
||||
state->last_engine = entry.engine;
|
||||
} else if (command->method >= 0x100) {
|
||||
|
@ -382,7 +397,7 @@ static void* pfifo_puller_thread()
|
|||
* TODO: Check this range is correct for the nv2a */
|
||||
if (command->method >= 0x180 && command->method < 0x200) {
|
||||
//qemu_mutex_lock_iothread();
|
||||
RAMHTEntry entry = ramht_lookup(parameter);
|
||||
RAMHTEntry entry = ramht_lookup(d, parameter);
|
||||
assert(entry.valid);
|
||||
assert(entry.channel_id == state->channel_id);
|
||||
parameter = entry.instance;
|
||||
|
@ -395,8 +410,8 @@ static void* pfifo_puller_thread()
|
|||
|
||||
switch (engine) {
|
||||
case ENGINE_GRAPHICS:
|
||||
pgraph_wait_fifo_access();
|
||||
pgraph_method(command->subchannel, command->method, parameter);
|
||||
pgraph_wait_fifo_access(d);
|
||||
pgraph_method(d, command->subchannel, command->method, parameter);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
|
@ -412,12 +427,12 @@ static void* pfifo_puller_thread()
|
|||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t ramht_hash(uint32_t handle)
|
||||
static uint32_t ramht_hash(NV2AState *d, uint32_t handle)
|
||||
{
|
||||
unsigned int ramht_size = 1 << (GET_MASK(pfifo.regs[NV_PFIFO_RAMHT], NV_PFIFO_RAMHT_SIZE_MASK) + 12);
|
||||
unsigned int ramht_size = 1 << (GET_MASK(d->pfifo.regs[NV_PFIFO_RAMHT], NV_PFIFO_RAMHT_SIZE_MASK) + 12);
|
||||
|
||||
/* XXX: Think this is different to what nouveau calculates... */
|
||||
unsigned int bits = ffs(ramht_size) - 2;
|
||||
|
@ -427,24 +442,23 @@ static uint32_t ramht_hash(uint32_t handle)
|
|||
hash ^= (handle & ((1 << bits) - 1));
|
||||
handle >>= bits;
|
||||
}
|
||||
hash ^= pfifo.cache1.channel_id << (bits - 4);
|
||||
hash ^= d->pfifo.cache1.channel_id << (bits - 4);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
static RAMHTEntry ramht_lookup(uint32_t handle)
|
||||
static RAMHTEntry ramht_lookup(NV2AState *d, uint32_t handle)
|
||||
{
|
||||
unsigned int ramht_size = 1 << (GET_MASK(pfifo.regs[NV_PFIFO_RAMHT], NV_PFIFO_RAMHT_SIZE_MASK) + 12);
|
||||
unsigned int ramht_size = 1 << (GET_MASK(d->pfifo.regs[NV_PFIFO_RAMHT], NV_PFIFO_RAMHT_SIZE_MASK) + 12);
|
||||
|
||||
uint32_t hash = ramht_hash(handle);
|
||||
uint32_t hash = ramht_hash(d, handle);
|
||||
assert(hash * 8 < ramht_size);
|
||||
|
||||
uint32_t ramht_address =
|
||||
GET_MASK(pfifo.regs[NV_PFIFO_RAMHT],
|
||||
GET_MASK(d->pfifo.regs[NV_PFIFO_RAMHT],
|
||||
NV_PFIFO_RAMHT_BASE_ADDRESS_MASK) << 12;
|
||||
|
||||
uint8_t *entry_ptr = (uint8_t*)(pramin.memory + ramht_address + hash * 8);
|
||||
uint8_t *entry_ptr = d->pramin.ramin_ptr + ramht_address + hash * 8;
|
||||
|
||||
uint32_t entry_handle = ldl_le_p((uint32_t*)entry_ptr);
|
||||
uint32_t entry_context = ldl_le_p((uint32_t*)(entry_ptr + 4));
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -8,14 +8,14 @@ DEVICE_READ32(PMC)
|
|||
result = 0; // When read, returns 0 if in little-endian mode, 0x01000001 if in big-endian mode.
|
||||
break;
|
||||
case NV_PMC_INTR_0: // Shows which functional units have pending IRQ
|
||||
result = pmc.pending_interrupts;
|
||||
result = d->pmc.pending_interrupts;
|
||||
break;
|
||||
case NV_PMC_INTR_EN_0: // Selects which functional units can cause IRQs
|
||||
result = pmc.enabled_interrupts;
|
||||
result = d->pmc.enabled_interrupts;
|
||||
break;
|
||||
default:
|
||||
result = 0;
|
||||
//DEVICE_READ32_REG(pmc); // Was : DEBUG_READ32_UNHANDLED(PMC);
|
||||
//DEVICE_READ32_REG(PMC); // Was : DEBUG_READ32_UNHANDLED(PMC);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -27,12 +27,12 @@ DEVICE_WRITE32(PMC)
|
|||
switch(addr) {
|
||||
case NV_PMC_INTR_0:
|
||||
/* the bits of the interrupts to clear are wrtten */
|
||||
pmc.pending_interrupts &= ~value;
|
||||
update_irq();
|
||||
d->pmc.pending_interrupts &= ~value;
|
||||
update_irq(d);
|
||||
break;
|
||||
case NV_PMC_INTR_EN_0:
|
||||
pmc.enabled_interrupts = value;
|
||||
update_irq();
|
||||
d->pmc.enabled_interrupts = value;
|
||||
update_irq(d);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -3,13 +3,13 @@ DEVICE_READ32(PRAMDAC)
|
|||
DEVICE_READ32_SWITCH() {
|
||||
|
||||
case NV_PRAMDAC_NVPLL_COEFF:
|
||||
result = pramdac.core_clock_coeff;
|
||||
result = d->pramdac.core_clock_coeff;
|
||||
break;
|
||||
case NV_PRAMDAC_MPLL_COEFF:
|
||||
result = pramdac.memory_clock_coeff;
|
||||
result = d->pramdac.memory_clock_coeff;
|
||||
break;
|
||||
case NV_PRAMDAC_VPLL_COEFF:
|
||||
result = pramdac.video_clock_coeff;
|
||||
result = d->pramdac.video_clock_coeff;
|
||||
break;
|
||||
case NV_PRAMDAC_PLL_TEST_COUNTER:
|
||||
/* emulated PLLs locked instantly? */
|
||||
|
@ -36,26 +36,26 @@ DEVICE_WRITE32(PRAMDAC)
|
|||
|
||||
uint32_t m, n, p;
|
||||
case NV_PRAMDAC_NVPLL_COEFF:
|
||||
pramdac.core_clock_coeff = value;
|
||||
d->pramdac.core_clock_coeff = value;
|
||||
|
||||
m = value & NV_PRAMDAC_NVPLL_COEFF_MDIV;
|
||||
n = (value & NV_PRAMDAC_NVPLL_COEFF_NDIV) >> 8;
|
||||
p = (value & NV_PRAMDAC_NVPLL_COEFF_PDIV) >> 16;
|
||||
|
||||
if (m == 0) {
|
||||
pramdac.core_clock_freq = 0;
|
||||
d->pramdac.core_clock_freq = 0;
|
||||
}
|
||||
else {
|
||||
pramdac.core_clock_freq = (NV2A_CRYSTAL_FREQ * n)
|
||||
d->pramdac.core_clock_freq = (NV2A_CRYSTAL_FREQ * n)
|
||||
/ (1 << p) / m;
|
||||
}
|
||||
|
||||
break;
|
||||
case NV_PRAMDAC_MPLL_COEFF:
|
||||
pramdac.memory_clock_coeff = value;
|
||||
d->pramdac.memory_clock_coeff = value;
|
||||
break;
|
||||
case NV_PRAMDAC_VPLL_COEFF:
|
||||
pramdac.video_clock_coeff = value;
|
||||
d->pramdac.video_clock_coeff = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -4,13 +4,13 @@ DEVICE_READ32(PRMCIO)
|
|||
DEVICE_READ32_SWITCH() {
|
||||
case VGA_CRT_IM:
|
||||
case VGA_CRT_IC:
|
||||
result = prmcio.cr_index;
|
||||
result = d->prmcio.cr_index;
|
||||
break;
|
||||
case VGA_CRT_DM:
|
||||
case VGA_CRT_DC:
|
||||
result = prmcio.cr[prmcio.cr_index];
|
||||
result = d->prmcio.cr[d->prmcio.cr_index];
|
||||
|
||||
printf("vga: read CR%x = 0x%02x\n", prmcio.cr_index, result);
|
||||
printf("vga: read CR%x = 0x%02x\n", d->prmcio.cr_index, result);
|
||||
break;
|
||||
default:
|
||||
DEBUG_READ32_UNHANDLED(PRMCIO);
|
||||
|
@ -39,18 +39,18 @@ DEVICE_WRITE32(PRMCIO)
|
|||
// vga_ioport_write :
|
||||
case VGA_CRT_IM:
|
||||
case VGA_CRT_IC:
|
||||
prmcio.cr_index = value;
|
||||
d->prmcio.cr_index = value;
|
||||
break;
|
||||
case VGA_CRT_DM:
|
||||
case VGA_CRT_DC:
|
||||
printf("vga: write CR%x = 0x%02x\n", prmcio.cr_index, value);
|
||||
printf("vga: write CR%x = 0x%02x\n", d->prmcio.cr_index, value);
|
||||
|
||||
/* handle CR0-7 protection */
|
||||
if ((prmcio.cr[VGA_CRTC_V_SYNC_END] & VGA_CR11_LOCK_CR0_CR7) &&
|
||||
prmcio.cr_index <= VGA_CRTC_OVERFLOW) {
|
||||
if ((d->prmcio.cr[VGA_CRTC_V_SYNC_END] & VGA_CR11_LOCK_CR0_CR7) &&
|
||||
d->prmcio.cr_index <= VGA_CRTC_OVERFLOW) {
|
||||
/* can always write bit 4 of CR7 */
|
||||
if (prmcio.cr_index == VGA_CRTC_OVERFLOW) {
|
||||
prmcio.cr[VGA_CRTC_OVERFLOW] = (prmcio.cr[VGA_CRTC_OVERFLOW] & ~0x10) |
|
||||
if (d->prmcio.cr_index == VGA_CRTC_OVERFLOW) {
|
||||
d->prmcio.cr[VGA_CRTC_OVERFLOW] = (d->prmcio.cr[VGA_CRTC_OVERFLOW] & ~0x10) |
|
||||
(value & 0x10);
|
||||
EmuWarning("TODO: vbe_update_vgaregs");
|
||||
//vbe_update_vgaregs();
|
||||
|
@ -58,11 +58,11 @@ DEVICE_WRITE32(PRMCIO)
|
|||
return;
|
||||
}
|
||||
|
||||
prmcio.cr[prmcio.cr_index] = value;
|
||||
d->prmcio.cr[d->prmcio.cr_index] = value;
|
||||
EmuWarning("TODO: vbe_update_vgaregs");
|
||||
//vbe_update_vgaregs();
|
||||
|
||||
switch (prmcio.cr_index) {
|
||||
switch (d->prmcio.cr_index) {
|
||||
case VGA_CRTC_H_TOTAL:
|
||||
case VGA_CRTC_H_SYNC_START:
|
||||
case VGA_CRTC_H_SYNC_END:
|
||||
|
|
|
@ -18,34 +18,34 @@ static inline uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
|
|||
}
|
||||
|
||||
/* PIMTER - time measurement and time-based alarms */
|
||||
static uint32_t ptimer_get_clock()
|
||||
static uint32_t ptimer_get_clock(NV2AState * d)
|
||||
{
|
||||
// Get time in nanoseconds
|
||||
long int time = static_cast<long int>(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count());
|
||||
|
||||
return muldiv64(time, pramdac.core_clock_freq * ptimer.numerator, CLOCKS_PER_SEC * ptimer.denominator);
|
||||
return muldiv64(time, d->pramdac.core_clock_freq * d->ptimer.numerator, CLOCKS_PER_SEC * d->ptimer.denominator);
|
||||
}
|
||||
|
||||
DEVICE_READ32(PTIMER)
|
||||
{
|
||||
DEVICE_READ32_SWITCH() {
|
||||
case NV_PTIMER_INTR_0:
|
||||
result = ptimer.pending_interrupts;
|
||||
result = d->ptimer.pending_interrupts;
|
||||
break;
|
||||
case NV_PTIMER_INTR_EN_0:
|
||||
result = ptimer.enabled_interrupts;
|
||||
result = d->ptimer.enabled_interrupts;
|
||||
break;
|
||||
case NV_PTIMER_NUMERATOR:
|
||||
result = ptimer.numerator;
|
||||
result = d->ptimer.numerator;
|
||||
break;
|
||||
case NV_PTIMER_DENOMINATOR:
|
||||
result = ptimer.denominator;
|
||||
result = d->ptimer.denominator;
|
||||
break;
|
||||
case NV_PTIMER_TIME_0:
|
||||
result = (ptimer_get_clock() & 0x7ffffff) << 5;
|
||||
result = (ptimer_get_clock(d) & 0x7ffffff) << 5;
|
||||
break;
|
||||
case NV_PTIMER_TIME_1:
|
||||
result = (ptimer_get_clock() >> 27) & 0x1fffffff;
|
||||
result = (ptimer_get_clock(d) >> 27) & 0x1fffffff;
|
||||
break;
|
||||
default:
|
||||
result = 0;
|
||||
|
@ -62,21 +62,21 @@ DEVICE_WRITE32(PTIMER)
|
|||
switch (addr) {
|
||||
|
||||
case NV_PTIMER_INTR_0:
|
||||
ptimer.pending_interrupts &= ~value;
|
||||
update_irq();
|
||||
d->ptimer.pending_interrupts &= ~value;
|
||||
update_irq(d);
|
||||
break;
|
||||
case NV_PTIMER_INTR_EN_0:
|
||||
ptimer.enabled_interrupts = value;
|
||||
update_irq();
|
||||
d->ptimer.enabled_interrupts = value;
|
||||
update_irq(d);
|
||||
break;
|
||||
case NV_PTIMER_DENOMINATOR:
|
||||
ptimer.denominator = value;
|
||||
d->ptimer.denominator = value;
|
||||
break;
|
||||
case NV_PTIMER_NUMERATOR:
|
||||
ptimer.numerator = value;
|
||||
d->ptimer.numerator = value;
|
||||
break;
|
||||
case NV_PTIMER_ALARM_0:
|
||||
ptimer.alarm_time = value;
|
||||
d->ptimer.alarm_time = value;
|
||||
break;
|
||||
default:
|
||||
//DEVICE_WRITE32_REG(ptimer); // Was : DEBUG_WRITE32_UNHANDLED(PTIMER);
|
||||
|
|
|
@ -29,12 +29,12 @@ DEVICE_WRITE32(PVIDEO)
|
|||
{
|
||||
switch (addr) {
|
||||
case NV_PVIDEO_BUFFER:
|
||||
pvideo.regs[addr] = value;
|
||||
d->pvideo.regs[addr] = value;
|
||||
// TODO: vga.enable_overlay = true;
|
||||
// pvideo_vga_invalidate(d);
|
||||
break;
|
||||
case NV_PVIDEO_STOP:
|
||||
pvideo.regs[NV_PVIDEO_BUFFER] = 0;
|
||||
d->pvideo.regs[NV_PVIDEO_BUFFER] = 0;
|
||||
// TODO: vga.enable_overlay = false;
|
||||
//pvideo_vga_invalidate(d);
|
||||
break;
|
||||
|
|
|
@ -3,9 +3,9 @@ DEVICE_READ32(USER)
|
|||
unsigned int channel_id = addr >> 16;
|
||||
assert(channel_id < NV2A_NUM_CHANNELS);
|
||||
|
||||
ChannelControl *control = &user.channel_control[channel_id];
|
||||
ChannelControl *control = &d->user.channel_control[channel_id];
|
||||
|
||||
uint32_t channel_modes = pfifo.regs[NV_PFIFO_MODE];
|
||||
uint32_t channel_modes = d->pfifo.regs[NV_PFIFO_MODE];
|
||||
|
||||
/* PIO Mode */
|
||||
if (!channel_modes & (1 << channel_id)) {
|
||||
|
@ -37,17 +37,17 @@ DEVICE_WRITE32(USER)
|
|||
unsigned int channel_id = addr >> 16;
|
||||
assert(channel_id < NV2A_NUM_CHANNELS);
|
||||
|
||||
ChannelControl *control = &user.channel_control[channel_id];
|
||||
ChannelControl *control = &d->user.channel_control[channel_id];
|
||||
|
||||
uint32_t channel_modes = pfifo.regs[NV_PFIFO_MODE];
|
||||
uint32_t channel_modes = d->pfifo.regs[NV_PFIFO_MODE];
|
||||
if (channel_modes & (1 << channel_id)) {
|
||||
/* DMA Mode */
|
||||
switch (addr & 0xFFFF) {
|
||||
case NV_USER_DMA_PUT:
|
||||
control->dma_put = value;
|
||||
|
||||
if (pfifo.cache1.push_enabled) {
|
||||
pfifo_run_pusher();
|
||||
if (d->pfifo.cache1.push_enabled) {
|
||||
pfifo_run_pusher(d);
|
||||
}
|
||||
break;
|
||||
case NV_USER_DMA_GET:
|
||||
|
|
|
@ -34,11 +34,504 @@
|
|||
// ******************************************************************
|
||||
#pragma once
|
||||
|
||||
#include "Cxbx.h" // For xbaddr
|
||||
#include "devices\PCIDevice.h" // For PCIDevice
|
||||
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
#include "nv2a_int.h"
|
||||
|
||||
#define NV2A_ADDR 0xFD000000
|
||||
#define NV2A_SIZE 0x01000000
|
||||
|
||||
#define NV_PMC_SIZE 0x001000
|
||||
#define _NV_PFIFO_SIZE 0x002000 // Underscore prefix to prevent clash with NV_PFIFO_SIZE
|
||||
#define NV_PVIDEO_SIZE 0x001000
|
||||
#define NV_PTIMER_SIZE 0x001000
|
||||
#define NV_PFB_SIZE 0x001000
|
||||
#define NV_PGRAPH_SIZE 0x002000
|
||||
#define NV_PCRTC_SIZE 0x001000
|
||||
#define NV_PRAMDAC_SIZE 0x001000
|
||||
#define NV_PRAMIN_ADDR 0x00700000
|
||||
#define NV_PRAMIN_SIZE 0x100000
|
||||
|
||||
typedef xbaddr hwaddr; // Compatibility; Cxbx uses xbaddr, xqemu and OpenXbox use hwaddr
|
||||
typedef uint32_t value_t; // Compatibility; Cxbx values are uint32_t (xqemu and OpenXbox use uint64_t)
|
||||
|
||||
|
||||
#define USE_TEXTURE_CACHE
|
||||
|
||||
// Public Domain ffs Implementation
|
||||
// See: http://snipplr.com/view/22147/stringsh-implementation/
|
||||
constexpr int ffs(int v)
|
||||
{
|
||||
unsigned int x = v;
|
||||
int c = 1;
|
||||
|
||||
/*
|
||||
* adapted from from
|
||||
* http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightBinSearch
|
||||
*
|
||||
* a modified binary search algorithm to count 0 bits from
|
||||
* the right (lsb). This algorithm should work regardless
|
||||
* of the size of ints on the platform.
|
||||
*
|
||||
*/
|
||||
|
||||
/* a couple special cases */
|
||||
if (x == 0) return 0;
|
||||
if (x & 1) return 1; /* probably pretty common */
|
||||
|
||||
c = 1;
|
||||
while ((x & 0xffff) == 0) {
|
||||
x >>= 16;
|
||||
c += 16;
|
||||
}
|
||||
if ((x & 0xff) == 0) {
|
||||
x >>= 8;
|
||||
c += 8;
|
||||
}
|
||||
if ((x & 0x0f) == 0) {
|
||||
x >>= 4;
|
||||
c += 4;
|
||||
}
|
||||
if ((x & 0x03) == 0) {
|
||||
x >>= 2;
|
||||
c += 2;
|
||||
}
|
||||
|
||||
c -= (x & 1);
|
||||
c += 1; /* ffs() requires indexing bits from 1 */
|
||||
/* ie., the lsb is bit 1, not bit 0 */
|
||||
return c;
|
||||
}
|
||||
|
||||
inline int GET_MASK(int v, int mask) {
|
||||
return (((v) & (mask)) >> (ffs(mask) - 1));
|
||||
};
|
||||
|
||||
inline int SET_MASK(int v, int mask, int val) {
|
||||
const unsigned int __val = (val);
|
||||
const unsigned int __mask = (mask);
|
||||
|
||||
(v) &= ~(__mask);
|
||||
return (v) |= ((__val) << (ffs(__mask)-1)) & (__mask);
|
||||
}
|
||||
|
||||
#define CASE_4(v, step) \
|
||||
case (v): \
|
||||
case (v)+(step) : \
|
||||
case (v)+(step) * 2: \
|
||||
case (v)+(step) * 3
|
||||
|
||||
|
||||
#define NV2A_DEVICE(obj) \
|
||||
OBJECT_CHECK(NV2AState, (obj), "nv2a")
|
||||
|
||||
//void reg_log_read(int block, hwaddr addr, uint64_t val);
|
||||
//void reg_log_write(int block, hwaddr addr, uint64_t val);
|
||||
|
||||
enum FifoMode {
|
||||
FIFO_PIO = 0,
|
||||
FIFO_DMA = 1,
|
||||
};
|
||||
|
||||
enum FIFOEngine {
|
||||
ENGINE_SOFTWARE = 0,
|
||||
ENGINE_GRAPHICS = 1,
|
||||
ENGINE_DVD = 2,
|
||||
};
|
||||
|
||||
typedef struct DMAObject {
|
||||
unsigned int dma_class;
|
||||
unsigned int dma_target;
|
||||
xbaddr address;
|
||||
xbaddr limit;
|
||||
} DMAObject;
|
||||
|
||||
typedef struct VertexAttribute {
|
||||
bool dma_select;
|
||||
xbaddr offset;
|
||||
|
||||
/* inline arrays are packed in order?
|
||||
* Need to pass the offset to converted attributes */
|
||||
unsigned int inline_array_offset;
|
||||
|
||||
float inline_value[4];
|
||||
|
||||
unsigned int format;
|
||||
unsigned int size; /* size of the data type */
|
||||
unsigned int count; /* number of components */
|
||||
uint32_t stride;
|
||||
|
||||
bool needs_conversion;
|
||||
uint8_t *converted_buffer;
|
||||
unsigned int converted_elements;
|
||||
unsigned int converted_size;
|
||||
unsigned int converted_count;
|
||||
|
||||
float *inline_buffer;
|
||||
|
||||
GLint gl_count;
|
||||
GLenum gl_type;
|
||||
GLboolean gl_normalize;
|
||||
|
||||
GLuint gl_converted_buffer;
|
||||
GLuint gl_inline_buffer;
|
||||
} VertexAttribute;
|
||||
|
||||
typedef struct Surface {
|
||||
bool draw_dirty;
|
||||
bool buffer_dirty;
|
||||
bool write_enabled_cache;
|
||||
unsigned int pitch;
|
||||
|
||||
xbaddr offset;
|
||||
} Surface;
|
||||
|
||||
typedef struct SurfaceShape {
|
||||
unsigned int z_format;
|
||||
unsigned int color_format;
|
||||
unsigned int zeta_format;
|
||||
unsigned int log_width, log_height;
|
||||
unsigned int clip_x, clip_y;
|
||||
unsigned int clip_width, clip_height;
|
||||
unsigned int anti_aliasing;
|
||||
} SurfaceShape;
|
||||
|
||||
typedef struct TextureShape {
|
||||
bool cubemap;
|
||||
unsigned int dimensionality;
|
||||
unsigned int color_format;
|
||||
unsigned int levels;
|
||||
unsigned int width, height, depth;
|
||||
|
||||
unsigned int min_mipmap_level, max_mipmap_level;
|
||||
unsigned int pitch;
|
||||
} TextureShape;
|
||||
|
||||
typedef struct TextureKey {
|
||||
TextureShape state;
|
||||
uint64_t data_hash;
|
||||
uint8_t* texture_data;
|
||||
uint8_t* palette_data;
|
||||
} TextureKey;
|
||||
|
||||
typedef struct TextureBinding {
|
||||
GLenum gl_target;
|
||||
GLuint gl_texture;
|
||||
unsigned int refcnt;
|
||||
} TextureBinding;
|
||||
|
||||
typedef struct KelvinState {
|
||||
xbaddr dma_notifies;
|
||||
xbaddr dma_state;
|
||||
xbaddr dma_semaphore;
|
||||
unsigned int semaphore_offset;
|
||||
} KelvinState;
|
||||
|
||||
typedef struct ContextSurfaces2DState {
|
||||
xbaddr dma_image_source;
|
||||
xbaddr dma_image_dest;
|
||||
unsigned int color_format;
|
||||
unsigned int source_pitch, dest_pitch;
|
||||
xbaddr source_offset, dest_offset;
|
||||
|
||||
} ContextSurfaces2DState;
|
||||
|
||||
typedef struct ImageBlitState {
|
||||
xbaddr context_surfaces;
|
||||
unsigned int operation;
|
||||
unsigned int in_x, in_y;
|
||||
unsigned int out_x, out_y;
|
||||
unsigned int width, height;
|
||||
|
||||
} ImageBlitState;
|
||||
|
||||
typedef struct GraphicsObject {
|
||||
uint8_t graphics_class;
|
||||
union {
|
||||
ContextSurfaces2DState context_surfaces_2d;
|
||||
|
||||
ImageBlitState image_blit;
|
||||
|
||||
KelvinState kelvin;
|
||||
} data;
|
||||
} GraphicsObject;
|
||||
|
||||
typedef struct GraphicsSubchannel {
|
||||
xbaddr object_instance;
|
||||
GraphicsObject object;
|
||||
uint32_t object_cache[5];
|
||||
} GraphicsSubchannel;
|
||||
|
||||
typedef struct GraphicsContext {
|
||||
bool channel_3d;
|
||||
unsigned int subchannel;
|
||||
} GraphicsContext;
|
||||
|
||||
|
||||
typedef struct PGRAPHState {
|
||||
std::mutex mutex;
|
||||
|
||||
uint32_t pending_interrupts;
|
||||
uint32_t enabled_interrupts;
|
||||
std::condition_variable interrupt_cond;
|
||||
|
||||
xbaddr context_table;
|
||||
xbaddr context_address;
|
||||
|
||||
|
||||
unsigned int trapped_method;
|
||||
unsigned int trapped_subchannel;
|
||||
unsigned int trapped_channel_id;
|
||||
uint32_t trapped_data[2];
|
||||
uint32_t notify_source;
|
||||
|
||||
bool fifo_access;
|
||||
std::condition_variable fifo_access_cond;
|
||||
std::condition_variable flip_3d;
|
||||
|
||||
unsigned int channel_id;
|
||||
bool channel_valid;
|
||||
GraphicsContext context[NV2A_NUM_CHANNELS];
|
||||
|
||||
xbaddr dma_color, dma_zeta;
|
||||
Surface surface_color, surface_zeta;
|
||||
unsigned int surface_type;
|
||||
SurfaceShape surface_shape;
|
||||
SurfaceShape last_surface_shape;
|
||||
|
||||
xbaddr dma_a, dma_b;
|
||||
//GLruCache *texture_cache;
|
||||
bool texture_dirty[NV2A_MAX_TEXTURES];
|
||||
TextureBinding *texture_binding[NV2A_MAX_TEXTURES];
|
||||
|
||||
//GHashTable *shader_cache;
|
||||
//ShaderBinding *shader_binding;
|
||||
|
||||
bool texture_matrix_enable[NV2A_MAX_TEXTURES];
|
||||
|
||||
/* FIXME: Move to NV_PGRAPH_BUMPMAT... */
|
||||
float bump_env_matrix[NV2A_MAX_TEXTURES - 1][4]; /* 3 allowed stages with 2x2 matrix each */
|
||||
|
||||
// wglContext *gl_context;
|
||||
GLuint gl_framebuffer;
|
||||
GLuint gl_color_buffer, gl_zeta_buffer;
|
||||
GraphicsSubchannel subchannel_data[NV2A_NUM_SUBCHANNELS];
|
||||
|
||||
xbaddr dma_report;
|
||||
xbaddr report_offset;
|
||||
bool zpass_pixel_count_enable;
|
||||
unsigned int zpass_pixel_count_result;
|
||||
unsigned int gl_zpass_pixel_count_query_count;
|
||||
GLuint* gl_zpass_pixel_count_queries;
|
||||
|
||||
xbaddr dma_vertex_a, dma_vertex_b;
|
||||
|
||||
unsigned int primitive_mode;
|
||||
|
||||
bool enable_vertex_program_write;
|
||||
|
||||
//uint32_t program_data[NV2A_MAX_TRANSFORM_PROGRAM_LENGTH][VSH_TOKEN_SIZE];
|
||||
|
||||
uint32_t vsh_constants[NV2A_VERTEXSHADER_CONSTANTS][4];
|
||||
bool vsh_constants_dirty[NV2A_VERTEXSHADER_CONSTANTS];
|
||||
|
||||
/* lighting constant arrays */
|
||||
uint32_t ltctxa[NV2A_LTCTXA_COUNT][4];
|
||||
bool ltctxa_dirty[NV2A_LTCTXA_COUNT];
|
||||
uint32_t ltctxb[NV2A_LTCTXB_COUNT][4];
|
||||
bool ltctxb_dirty[NV2A_LTCTXB_COUNT];
|
||||
uint32_t ltc1[NV2A_LTC1_COUNT][4];
|
||||
bool ltc1_dirty[NV2A_LTC1_COUNT];
|
||||
|
||||
// should figure out where these are in lighting context
|
||||
float light_infinite_half_vector[NV2A_MAX_LIGHTS][3];
|
||||
float light_infinite_direction[NV2A_MAX_LIGHTS][3];
|
||||
float light_local_position[NV2A_MAX_LIGHTS][3];
|
||||
float light_local_attenuation[NV2A_MAX_LIGHTS][3];
|
||||
|
||||
//VertexAttribute vertex_attributes[NV2A_VERTEXSHADER_ATTRIBUTES];
|
||||
|
||||
unsigned int inline_array_length;
|
||||
uint32_t inline_array[NV2A_MAX_BATCH_LENGTH];
|
||||
GLuint gl_inline_array_buffer;
|
||||
|
||||
unsigned int inline_elements_length;
|
||||
uint32_t inline_elements[NV2A_MAX_BATCH_LENGTH];
|
||||
|
||||
unsigned int inline_buffer_length;
|
||||
|
||||
unsigned int draw_arrays_length;
|
||||
unsigned int draw_arrays_max_count;
|
||||
|
||||
/* FIXME: Unknown size, possibly endless, 1000 will do for now */
|
||||
GLint gl_draw_arrays_start[1000];
|
||||
GLsizei gl_draw_arrays_count[1000];
|
||||
|
||||
GLuint gl_element_buffer;
|
||||
GLuint gl_memory_buffer;
|
||||
GLuint gl_vertex_array;
|
||||
|
||||
uint32_t regs[NV_PGRAPH_SIZE]; // TODO : union
|
||||
} PGRAPHState;
|
||||
|
||||
|
||||
typedef struct CacheEntry {
|
||||
//QSIMPLEQ_ENTRY(CacheEntry) entry;
|
||||
unsigned int method : 14;
|
||||
unsigned int subchannel : 3;
|
||||
bool nonincreasing;
|
||||
uint32_t parameter;
|
||||
} CacheEntry;
|
||||
|
||||
typedef struct Cache1State {
|
||||
unsigned int channel_id;
|
||||
FifoMode mode;
|
||||
|
||||
/* Pusher state */
|
||||
bool push_enabled;
|
||||
bool dma_push_enabled;
|
||||
bool dma_push_suspended;
|
||||
xbaddr dma_instance;
|
||||
|
||||
bool method_nonincreasing;
|
||||
unsigned int method : 14;
|
||||
unsigned int subchannel : 3;
|
||||
unsigned int method_count : 24;
|
||||
uint32_t dcount;
|
||||
|
||||
bool subroutine_active;
|
||||
xbaddr subroutine_return;
|
||||
xbaddr get_jmp_shadow;
|
||||
uint32_t rsvd_shadow;
|
||||
uint32_t data_shadow;
|
||||
uint32_t error;
|
||||
|
||||
bool pull_enabled;
|
||||
enum FIFOEngine bound_engines[NV2A_NUM_SUBCHANNELS];
|
||||
enum FIFOEngine last_engine;
|
||||
|
||||
/* The actual command queue */
|
||||
std::mutex mutex;
|
||||
std::condition_variable cache_cond;
|
||||
std::queue<CacheEntry*> cache;
|
||||
std::queue<CacheEntry*> working_cache;
|
||||
} Cache1State;
|
||||
|
||||
typedef struct ChannelControl {
|
||||
xbaddr dma_put;
|
||||
xbaddr dma_get;
|
||||
uint32_t ref;
|
||||
} ChannelControl;
|
||||
|
||||
typedef struct NV2AState {
|
||||
// PCIDevice dev;
|
||||
// qemu_irq irq;
|
||||
bool exiting;
|
||||
|
||||
// VGACommonState vga;
|
||||
// GraphicHwOps hw_ops;
|
||||
// QEMUTimer *vblank_timer;
|
||||
|
||||
// MemoryRegion *vram;
|
||||
// MemoryRegion vram_pci;
|
||||
uint8_t *vram_ptr;
|
||||
size_t vram_size;
|
||||
// MemoryRegion ramin;
|
||||
struct {
|
||||
uint8_t *ramin_ptr;
|
||||
size_t ramin_size;
|
||||
uint32_t regs[NV_PRAMIN_SIZE]; // TODO : union
|
||||
} pramin;
|
||||
|
||||
// MemoryRegion mmio;
|
||||
// MemoryRegion block_mmio[NV_NUM_BLOCKS];
|
||||
|
||||
struct {
|
||||
uint32_t pending_interrupts;
|
||||
uint32_t enabled_interrupts;
|
||||
uint32_t regs[NV_PMC_SIZE]; // TODO : union
|
||||
} pmc;
|
||||
|
||||
struct {
|
||||
std::thread puller_thread;
|
||||
uint32_t pending_interrupts;
|
||||
uint32_t enabled_interrupts;
|
||||
Cache1State cache1;
|
||||
uint32_t regs[_NV_PFIFO_SIZE]; // TODO : union
|
||||
} pfifo;
|
||||
|
||||
struct {
|
||||
uint32_t regs[NV_PVIDEO_SIZE]; // TODO : union
|
||||
} pvideo;
|
||||
|
||||
struct {
|
||||
uint32_t pending_interrupts;
|
||||
uint32_t enabled_interrupts;
|
||||
uint32_t numerator;
|
||||
uint32_t denominator;
|
||||
uint32_t alarm_time;
|
||||
uint32_t regs[NV_PTIMER_SIZE]; // TODO : union
|
||||
} ptimer;
|
||||
|
||||
struct {
|
||||
uint32_t regs[NV_PFB_SIZE]; // TODO : union
|
||||
} pfb;
|
||||
|
||||
struct PGRAPHState pgraph;
|
||||
|
||||
struct {
|
||||
uint32_t pending_interrupts;
|
||||
uint32_t enabled_interrupts;
|
||||
hwaddr start;
|
||||
uint32_t regs[NV_PCRTC_SIZE]; // TODO : union
|
||||
} pcrtc;
|
||||
|
||||
struct {
|
||||
uint32_t core_clock_coeff;
|
||||
uint64_t core_clock_freq;
|
||||
uint32_t memory_clock_coeff;
|
||||
uint32_t video_clock_coeff;
|
||||
uint32_t regs[NV_PRAMDAC_SIZE]; // TODO : union
|
||||
} pramdac;
|
||||
|
||||
struct {
|
||||
ChannelControl channel_control[NV2A_NUM_CHANNELS];
|
||||
} user;
|
||||
|
||||
// PRMCIO (Actually the VGA controller)
|
||||
struct {
|
||||
uint8_t cr_index;
|
||||
uint8_t cr[256]; /* CRT registers */
|
||||
} prmcio;
|
||||
|
||||
std::mutex io_lock;
|
||||
//SDL_Window *sdl_window;
|
||||
|
||||
} NV2AState;
|
||||
|
||||
typedef value_t(*read_func)(NV2AState *d, hwaddr addr); //, unsigned int size);
|
||||
typedef void(*write_func)(NV2AState *d, hwaddr addr, value_t val); //, unsigned int size);
|
||||
|
||||
typedef struct {
|
||||
read_func read;
|
||||
write_func write;
|
||||
} MemoryRegionOps;
|
||||
|
||||
typedef struct NV2ABlockInfo {
|
||||
const char* name;
|
||||
hwaddr offset;
|
||||
uint64_t size;
|
||||
MemoryRegionOps ops;
|
||||
} NV2ABlockInfo;
|
||||
|
||||
class NV2ADevice : public PCIDevice {
|
||||
public:
|
||||
// PCI Device functions
|
||||
|
|
Loading…
Reference in New Issue