NV2A : Copied over all PGRAPH code from XQEMU / OpenXbox. All OpenGL-calls are still disabled.

This commit is contained in:
PatrickvL 2018-02-02 15:35:50 +01:00
parent 0ac96332a7
commit 4e07867c47
8 changed files with 3426 additions and 355 deletions

View File

@ -642,6 +642,10 @@ static void nv2a_vblank_thread(NV2AState *d)
}
}
// See NV2ABlockInfo regions[] PRAMIN
#define NV_PRAMIN_ADDR 0x00700000
#define NV_PRAMIN_SIZE 0x100000
void CxbxReserveNV2AMemory(NV2AState *d)
{
// Reserve NV2A memory :
@ -673,7 +677,7 @@ void CxbxReserveNV2AMemory(NV2AState *d)
}
printf("[0x%.4X] INIT: Allocated %d MiB of Xbox NV2A PRAMIN memory at 0x%.8X to 0x%.8X\n",
GetCurrentThreadId(), NV_PRAMIN_SIZE / ONE_MB, NV2A_ADDR + NV_PRAMIN_ADDR, NV2A_ADDR + NV_PRAMIN_ADDR + NV_PRAMIN_SIZE - 1);
GetCurrentThreadId(), d->pramin.ramin_size / ONE_MB, d->pramin.ramin_ptr, d->pramin.ramin_ptr + d->pramin.ramin_size - 1);
}
void EmuNV2A_Init()
@ -682,6 +686,7 @@ void EmuNV2A_Init()
d->pcrtc.start = 0;
d->vram_ptr = (uint8_t*)MM_SYSTEM_PHYSICAL_MAP;
d->vram_size = (g_bIsChihiro || g_bIsDebug) ? CONTIGUOUS_MEMORY_CHIHIRO_SIZE : CONTIGUOUS_MEMORY_XBOX_SIZE;
d->pramdac.core_clock_coeff = 0x00011c01; /* 189MHz...? */

View File

@ -36,13 +36,13 @@ DEVICE_READ32(PFIFO)
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: {
case NV_PFIFO_CACHE1_STATUS:
d->pfifo.cache1.cache_lock.lock();
if (d->pfifo.cache1.cache.empty()) {
result |= NV_PFIFO_CACHE1_STATUS_LOW_MARK; /* low mark empty */
}
d->pfifo.cache1.cache_lock.unlock();
} break;
break;
case NV_PFIFO_CACHE1_DMA_PUSH:
SET_MASK(result, NV_PFIFO_CACHE1_DMA_PUSH_ACCESS,
d->pfifo.cache1.dma_push_enabled);
@ -76,18 +76,18 @@ DEVICE_READ32(PFIFO)
result = d->pfifo.cache1.subroutine_return
| d->pfifo.cache1.subroutine_active;
break;
case NV_PFIFO_CACHE1_PULL0: {
case NV_PFIFO_CACHE1_PULL0:
d->pfifo.cache1.cache_lock.lock();
result = d->pfifo.cache1.pull_enabled;
d->pfifo.cache1.cache_lock.unlock();
} break;
case NV_PFIFO_CACHE1_ENGINE: {
break;
case NV_PFIFO_CACHE1_ENGINE:
d->pfifo.cache1.cache_lock.lock();
for (int i = 0; i < NV2A_NUM_SUBCHANNELS; i++) {
result |= d->pfifo.cache1.bound_engines[i] << (i * 2);
}
d->pfifo.cache1.cache_lock.unlock();
} break;
break;
case NV_PFIFO_CACHE1_DMA_DCOUNT:
result = d->pfifo.cache1.dcount;
break;
@ -110,6 +110,8 @@ DEVICE_READ32(PFIFO)
DEVICE_WRITE32(PFIFO)
{
int i;
switch(addr) {
case NV_PFIFO_INTR_0:
d->pfifo.pending_interrupts &= ~value;
@ -128,22 +130,31 @@ DEVICE_WRITE32(PFIFO)
assert(d->pfifo.cache1.channel_id < NV2A_NUM_CHANNELS);
break;
case NV_PFIFO_CACHE1_DMA_PUSH:
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_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);
}
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:
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);
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:
d->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:
d->user.channel_control[d->pfifo.cache1.channel_id].dma_put = value;
@ -152,12 +163,13 @@ DEVICE_WRITE32(PFIFO)
d->user.channel_control[d->pfifo.cache1.channel_id].dma_get = value;
break;
case NV_PFIFO_CACHE1_DMA_SUBROUTINE:
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);
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: {
case NV_PFIFO_CACHE1_PULL0:
d->pfifo.cache1.cache_lock.lock();
if ((value & NV_PFIFO_CACHE1_PULL0_ACCESS)
&& !d->pfifo.cache1.pull_enabled) {
d->pfifo.cache1.pull_enabled = true;
@ -169,19 +181,21 @@ DEVICE_WRITE32(PFIFO)
d->pfifo.cache1.pull_enabled = false;
}
d->pfifo.cache1.cache_lock.unlock();
} break;
case NV_PFIFO_CACHE1_ENGINE: {
break;
case NV_PFIFO_CACHE1_ENGINE:
d->pfifo.cache1.cache_lock.lock();
for (int i = 0; i < NV2A_NUM_SUBCHANNELS; i++) {
for (i=0; i < NV2A_NUM_SUBCHANNELS; i++) {
d->pfifo.cache1.bound_engines[i] = (FIFOEngine)((value >> (i * 2)) & 3);
}
d->pfifo.cache1.cache_lock.unlock();
} break;
break;
case NV_PFIFO_CACHE1_DMA_DCOUNT:
d->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:
d->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:
d->pfifo.cache1.rsvd_shadow = value;
@ -197,6 +211,7 @@ DEVICE_WRITE32(PFIFO)
DEVICE_WRITE32_END(PFIFO);
}
/* pusher should be fine to run from a mimo handler
* whenever's it's convenient */
static void pfifo_run_pusher(NV2AState *d) {
@ -215,6 +230,7 @@ static void pfifo_run_pusher(NV2AState *d) {
if (!state->push_enabled) return;
/* only handling DMA for now... */
/* Channel running DMA */
@ -230,12 +246,13 @@ static void pfifo_run_pusher(NV2AState *d) {
dma = (uint8_t*)nv_dma_map(d, state->dma_instance, &dma_len);
printf("DMA pusher: max 0x%08X, 0x%08X - 0x%08X\n",
NV2A_DPRINTF("DMA pusher: max 0x%08X, 0x%08X - 0x%08X\n",
dma_len, control->dma_get, control->dma_put);
/* based on the convenient pseudocode in envytools */
while (control->dma_get != control->dma_put) {
if (control->dma_get >= dma_len) {
state->error = NV_PFIFO_CACHE1_DMA_STATE_ERROR_PROTECTION;
break;
}
@ -247,7 +264,7 @@ static void pfifo_run_pusher(NV2AState *d) {
/* data word of methods command */
state->data_shadow = word;
command = (CacheEntry*)calloc(1, sizeof(CacheEntry));
command = (CacheEntry*)malloc(sizeof(CacheEntry));
command->method = state->method;
command->subchannel = state->subchannel;
command->nonincreasing = state->method_nonincreasing;
@ -271,15 +288,13 @@ static void pfifo_run_pusher(NV2AState *d) {
/* old jump */
state->get_jmp_shadow = control->dma_get;
control->dma_get = word & 0x1fffffff;
printf("pb OLD_JMP 0x%08X\n", control->dma_get);
}
else if ((word & 3) == 1) {
NV2A_DPRINTF("pb OLD_JMP 0x%08X\n", control->dma_get);
} else if ((word & 3) == 1) {
/* jump */
state->get_jmp_shadow = control->dma_get;
control->dma_get = word & 0xfffffffc;
printf("pb JMP 0x%08X\n", control->dma_get);
}
else if ((word & 3) == 2) {
NV2A_DPRINTF("pb JMP 0x%08X\n", control->dma_get);
} else if ((word & 3) == 2) {
/* call */
if (state->subroutine_active) {
state->error = NV_PFIFO_CACHE1_DMA_STATE_ERROR_CALL;
@ -288,9 +303,8 @@ static void pfifo_run_pusher(NV2AState *d) {
state->subroutine_return = control->dma_get;
state->subroutine_active = true;
control->dma_get = word & 0xfffffffc;
printf("pb CALL 0x%08X\n", control->dma_get);
}
else if (word == 0x00020000) {
NV2A_DPRINTF("pb CALL 0x%08X\n", control->dma_get);
} else if (word == 0x00020000) {
/* return */
if (!state->subroutine_active) {
state->error = NV_PFIFO_CACHE1_DMA_STATE_ERROR_RETURN;
@ -298,9 +312,8 @@ static void pfifo_run_pusher(NV2AState *d) {
}
control->dma_get = state->subroutine_return;
state->subroutine_active = false;
printf("pb RET 0x%08X\n", control->dma_get);
}
else if ((word & 0xe0030003) == 0) {
NV2A_DPRINTF("pb RET 0x%08X\n", control->dma_get);
} else if ((word & 0xe0030003) == 0) {
/* increasing methods */
state->method = word & 0x1fff;
state->subchannel = (word >> 13) & 7;
@ -315,9 +328,8 @@ static void pfifo_run_pusher(NV2AState *d) {
state->method_count = (word >> 18) & 0x7ff;
state->method_nonincreasing = true;
state->dcount = 0;
}
else {
printf("pb reserved cmd 0x%08X - 0x%08X\n",
} else {
NV2A_DPRINTF("pb reserved cmd 0x%08X - 0x%08X\n",
control->dma_get, word);
state->error = NV_PFIFO_CACHE1_DMA_STATE_ERROR_RESERVED_CMD;
break;
@ -325,11 +337,11 @@ static void pfifo_run_pusher(NV2AState *d) {
}
}
printf("DMA pusher done: max 0x%08X, 0x%08X - 0x%08X\n",
NV2A_DPRINTF("DMA pusher done: max 0x%08X, 0x%08X - 0x%08X\n",
dma_len, control->dma_get, control->dma_put);
if (state->error) {
printf("pb error: %d\n", state->error);
NV2A_DPRINTF("pb error: %d\n", state->error);
assert(false);
state->dma_push_suspended = true;
@ -345,6 +357,8 @@ int pfifo_puller_thread(NV2AState *d)
Cache1State *state = &d->pfifo.cache1;
// glo_set_current(d->pgraph.gl_context);
while (true) {
state->cache_lock.lock();
while (state->cache.empty() || !state->pull_enabled) {
@ -411,7 +425,8 @@ int pfifo_puller_thread(NV2AState *d)
switch (engine) {
case ENGINE_GRAPHICS:
pgraph_wait_fifo_access(d);
pgraph_method(d, command->subchannel, command->method, parameter);
pgraph_method(d, command->subchannel,
command->method, parameter);
break;
default:
assert(false);
@ -425,17 +440,17 @@ int pfifo_puller_thread(NV2AState *d)
free(command);
}
d->pgraph.lock.unlock();
}
d->pgraph.lock.unlock();
return 0;
}
static uint32_t ramht_hash(NV2AState *d, uint32_t handle)
{
unsigned int ramht_size = 1 << (GET_MASK(d->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;
@ -452,7 +467,8 @@ static uint32_t ramht_hash(NV2AState *d, uint32_t handle)
static RAMHTEntry ramht_lookup(NV2AState *d, uint32_t handle)
{
unsigned int ramht_size = 1 << (GET_MASK(d->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(d, handle);
assert(hash * 8 < ramht_size);
@ -475,4 +491,3 @@ static RAMHTEntry ramht_lookup(NV2AState *d, uint32_t handle)
return entry;
}

File diff suppressed because it is too large Load Diff

View File

@ -44,8 +44,7 @@ DEVICE_WRITE32(PRAMDAC)
if (m == 0) {
d->pramdac.core_clock_freq = 0;
}
else {
} else {
d->pramdac.core_clock_freq = (NV2A_CRYSTAL_FREQ * n)
/ (1 << p) / m;
}

View File

@ -1,21 +1,13 @@
DEVICE_READ32(PRAMIN)
{
DEVICE_READ32_SWITCH() {
default:
DEVICE_READ32_REG(pramin);
break;
}
uint32_t result = *((uint32_t*)(d->pramin.ramin_ptr + addr));
DEVICE_READ32_END(PRAMIN);
}
DEVICE_WRITE32(PRAMIN)
{
switch (addr) {
default:
DEVICE_WRITE32_REG(pramin);
break;
}
*((uint32_t*)(d->pramin.ramin_ptr + addr)) = value;
DEVICE_WRITE32_END(PRAMIN);
}

View File

@ -1,15 +1,13 @@
/*
static void pvideo_vga_invalidate(NV2AState *d)
{
int y1 = GET_MASK(d->pvideo.regs[NV_PVIDEO_POINT_OUT],
int y1 = GET_MASK(d->pvideo.regs[NV_PVIDEO_POINT_OUT(0)],
NV_PVIDEO_POINT_OUT_Y);
int y2 = y1 + GET_MASK(d->pvideo.regs[NV_PVIDEO_SIZE_OUT],
int y2 = y1 + GET_MASK(d->pvideo.regs[NV_PVIDEO_SIZE_OUT(0)],
NV_PVIDEO_SIZE_OUT_HEIGHT);
NV2A_DPRINTF("pvideo_vga_invalidate %d %d\n", y1, y2);
vga_invalidate_scanlines(&d->vga, y1, y2);
// TODO : vga_invalidate_scanlines(&d->vga, y1, y2);
}
*/
DEVICE_READ32(PVIDEO)
{
DEVICE_READ32_SWITCH() {
@ -30,13 +28,13 @@ DEVICE_WRITE32(PVIDEO)
switch (addr) {
case NV_PVIDEO_BUFFER:
d->pvideo.regs[addr] = value;
// TODO: vga.enable_overlay = true;
// pvideo_vga_invalidate(d);
// TODO : d->vga.enable_overlay = true;
pvideo_vga_invalidate(d);
break;
case NV_PVIDEO_STOP:
d->pvideo.regs[NV_PVIDEO_BUFFER] = 0;
// TODO: vga.enable_overlay = false;
//pvideo_vga_invalidate(d);
// TODO : d->vga.enable_overlay = false;
pvideo_vga_invalidate(d);
break;
default:
DEVICE_WRITE32_REG(pvideo);

View File

@ -60,8 +60,7 @@ DEVICE_WRITE32(USER)
DEBUG_WRITE32_UNHANDLED(USER);
break;
}
}
else {
} else {
/* PIO Mode */
assert(false);
}

View File

@ -57,12 +57,13 @@
#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 NV2A_DPRINTF printf // Compatibility; TODO : Replace this by something equivalent
#define NV2A_GL_DPRINTF EmuWarning // Compatibility; TODO : Replace this by something equivalent
#define VSH_TOKEN_SIZE 4 // Compatibility; TODO : Move this to nv2a_vsh.h
//#define MAX(a,b) ((a)>(b) ? (a) : (b)) // Compatibility
#define USE_TEXTURE_CACHE
@ -123,12 +124,27 @@ inline int SET_MASK(int v, int mask, int val) {
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
// Power-of-two CASE statements
#define CASE_1(v, step) case (v)
#define CASE_2(v, step) CASE_1(v, step) : CASE_1(v + (step) * 1, step)
#define CASE_4(v, step) CASE_2(v, step) : CASE_2(v + (step) * 2, step)
#define CASE_8(v, step) CASE_4(v, step) : CASE_4(v + (step) * 4, step)
#define CASE_16(v, step) CASE_8(v, step) : CASE_8(v + (step) * 8, step)
#define CASE_32(v, step) CASE_16(v, step) : CASE_16(v + (step) * 16, step)
#define CASE_64(v, step) CASE_32(v, step) : CASE_32(v + (step) * 32, step)
#define CASE_128(v, step) CASE_64(v, step) : CASE_64(v + (step) * 64, step)
// Non-power-of-two CASE statements
#define CASE_3(v, step) CASE_2(v, step) : CASE_1(v + (step) * 2, step)
#define CASE_12(v, step) CASE_8(v, step) : CASE_4(v + (step) * 8, step)
#define CASE_13(v, step) CASE_8(v, step) : CASE_3(v + (step) * 8, step)
#define CASE_28(v, step) CASE_16(v, step) : CASE_12(v + (step) * 16, step)
#define CASE_29(v, step) CASE_16(v, step) : CASE_13(v + (step) * 16, step)
#define CASE_61(v, step) CASE_32(v, step) : CASE_29(v + (step) * 32, step)
#define CASE_78(v, step) CASE_64(v, step) : CASE_12(v + (step) * 64, step)
#define CASE_125(v, step) CASE_64(v, step) : CASE_61(v + (step) * 64, step)
#define CASE_132(v, step) CASE_128(v, step) : CASE_4(v + (step) * 128, step)
#define CASE_253(v, step) CASE_128(v, step) : CASE_125(v + (step) * 128, step)
#define NV2A_DEVICE(obj) \
OBJECT_CHECK(NV2AState, (obj), "nv2a")
@ -339,7 +355,7 @@ typedef struct PGRAPHState {
bool enable_vertex_program_write;
//uint32_t program_data[NV2A_MAX_TRANSFORM_PROGRAM_LENGTH][VSH_TOKEN_SIZE];
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];
@ -449,7 +465,6 @@ typedef struct NV2AState {
struct {
uint8_t *ramin_ptr;
size_t ramin_size;
uint32_t regs[NV_PRAMIN_SIZE]; // TODO : union
} pramin;
// MemoryRegion mmio;
@ -458,7 +473,7 @@ typedef struct NV2AState {
struct {
uint32_t pending_interrupts;
uint32_t enabled_interrupts;
uint32_t regs[NV_PMC_SIZE]; // TODO : union
uint32_t regs[NV_PMC_SIZE]; // Not in xqemu/openxbox? TODO : union
} pmc;
struct {
@ -479,7 +494,7 @@ typedef struct NV2AState {
uint32_t numerator;
uint32_t denominator;
uint32_t alarm_time;
uint32_t regs[NV_PTIMER_SIZE]; // TODO : union
uint32_t regs[NV_PTIMER_SIZE]; // Not in xqemu/openxbox? TODO : union
} ptimer;
struct {
@ -492,7 +507,7 @@ typedef struct NV2AState {
uint32_t pending_interrupts;
uint32_t enabled_interrupts;
hwaddr start;
uint32_t regs[NV_PCRTC_SIZE]; // TODO : union
uint32_t regs[NV_PCRTC_SIZE]; // Not in xqemu/openxbox? TODO : union
} pcrtc;
struct {
@ -500,7 +515,7 @@ typedef struct NV2AState {
uint64_t core_clock_freq;
uint32_t memory_clock_coeff;
uint32_t video_clock_coeff;
uint32_t regs[NV_PRAMDAC_SIZE]; // TODO : union
uint32_t regs[NV_PRAMDAC_SIZE]; // Not in xqemu/openxbox? TODO : union
} pramdac;
struct {
@ -511,9 +526,9 @@ typedef struct NV2AState {
struct {
uint8_t cr_index;
uint8_t cr[256]; /* CRT registers */
} prmcio;
} prmcio; // Not in xqemu/openxbox?
std::mutex io_lock;
std::mutex io_lock; // TODO ? std::unique_lock<std::mutex>
//SDL_Window *sdl_window;
} NV2AState;