Began porting NV2A emulation from XQEMU.

This commit is contained in:
Luke Usher 2016-10-28 19:57:13 +01:00
parent d424f0b004
commit 588aa5745b
1 changed files with 142 additions and 8 deletions

View File

@ -28,6 +28,11 @@
// *
// * (c) 2002-2003 Aaron Robinson <caustik@caustik.com>
// * (c) 2016 Luke Usher <luke.usher@outlook.com>
// *
// * EmuNV2A.cpp is heavily based on code from XQEMU
// * (c) XQEMU Team
// * https://github.com/espes/xqemu/blob/xbox/hw/xbox/nv2a.c
// *
// * All rights reserved
// *
// ******************************************************************
@ -41,9 +46,80 @@
#include "EmuNV2A.h"
#include "nv2a_int.h" // from https://github.com/espes/xqemu/tree/xbox/hw/xbox
struct {
uint32_t pending_interrupts;
uint32_t enabled_interrupts;
} pmc;
struct {
uint32_t pending_interrupts;
uint32_t enabled_interrupts;
//TODO:
// QemuThread puller_thread;
// Cache1State cache1;
uint32_t regs[0x2000];
} pfifo;
struct {
uint32_t regs[0x1000];
} pvideo;
struct {
uint32_t pending_interrupts;
uint32_t enabled_interrupts;
uint32_t numerator;
uint32_t denominator;
uint32_t alarm_time;
} ptimer;
struct {
uint32_t regs[0x1000];
} pfb;
struct {
uint32_t pending_interrupts;
uint32_t enabled_interrupts;
uint32_t start;
} pcrtc;
struct {
uint32_t core_clock_coeff;
uint64_t core_clock_freq;
uint32_t memory_clock_coeff;
uint32_t video_clock_coeff;
} pramdac;
static void update_irq()
{
/* PFIFO */
if (pfifo.pending_interrupts & pfifo.enabled_interrupts) {
pmc.pending_interrupts |= NV_PMC_INTR_0_PFIFO;
} else {
pmc.pending_interrupts &= ~NV_PMC_INTR_0_PFIFO;
}
if (pcrtc.pending_interrupts & pcrtc.enabled_interrupts) {
pmc.pending_interrupts |= NV_PMC_INTR_0_PCRTC;
} else {
pmc.pending_interrupts &= ~NV_PMC_INTR_0_PCRTC;
}
/* TODO PGRAPH */
/*
if (pgraph.pending_interrupts & pgraph.enabled_interrupts) {
pmc.pending_interrupts |= NV_PMC_INTR_0_PGRAPH;
} else {
pmc.pending_interrupts &= ~NV_PMC_INTR_0_PGRAPH;
} */
if (pmc.pending_interrupts && pmc.enabled_interrupts) {
// TODO Raise IRQ
EmuWarning("EmuNV2A: Raise IRQ Not Implemented");
} else {
// TODO: Cancel IRQ
EmuWarning("EmuNV2A: Cancel IRQ Not Implemented");
}
}
uint32_t EmuNV2A_PMC_Read32(uint32_t addr)
{
switch (addr) {
case NV_PMC_BOOT_0: // chipset and stepping: NV2A, A02, Rev 0 return 0x02A000A2;
case NV_PMC_INTR_0: return pmc.pending_interrupts;
case NV_PMC_INTR_EN_0:
return pmc.enabled_interrupts;
default:
EmuWarning("EmuNV2A_PMC_Read32: Unknown Read Address %08X", addr);
}
@ -57,7 +133,7 @@ uint32_t EmuNV2A_PBUS_Read32(uint32_t addr)
case NV_PBUS_PCI_NV_0:
return 0x10de; // PCI_VENDOR_ID_NVIDIA
case NV_PBUS_PCI_NV_2:
return 0x0; // NV_PBUS_PCI_NV_2_REVISION_ID ??
return (0x02 << 24) | 161; // PCI_CLASS_DISPLAY_3D (0x02) Rev 161 (0xA1)
default:
EmuWarning("EmuNV2A_PBUS_Read32: Unknown Read Address %08X", addr);
}
@ -98,8 +174,10 @@ uint32_t EmuNV2A_PRMA_Read32(uint32_t addr)
uint32_t EmuNV2A_PVIDEO_Read32(uint32_t addr)
{
switch (addr) {
case NV_PVIDEO_STOP:
return 0;
default:
EmuWarning("EmuNV2A_PVIDEO_Read32: Unknown Read Address %08X", addr);
return pvideo.regs[addr];
}
return 0;
@ -198,6 +276,12 @@ uint32_t EmuNV2A_PGRAPH_Read32(uint32_t addr)
uint32_t EmuNV2A_PCRTC_Read32(uint32_t addr)
{
switch (addr) {
case NV_PCRTC_INTR_0:
return pcrtc.pending_interrupts;
case NV_PCRTC_INTR_EN_0:
return pcrtc.enabled_interrupts;
case NV_PCRTC_START:
return pcrtc.start;
default:
EmuWarning("EmuNV2A_PCRTC_Read32: Unknown Read Address %08X", addr);
}
@ -217,7 +301,23 @@ uint32_t EmuNV2A_PRMCIO_Read32(uint32_t addr)
uint32_t EmuNV2A_PRAMDAC_Read32(uint32_t addr)
{
switch (addr) {
switch (addr & 3) {
case NV_PRAMDAC_NVPLL_COEFF:
return pramdac.core_clock_coeff;
break;
case NV_PRAMDAC_MPLL_COEFF:
return pramdac.memory_clock_coeff;
break;
case NV_PRAMDAC_VPLL_COEFF:
return pramdac.video_clock_coeff;
break;
case NV_PRAMDAC_PLL_TEST_COUNTER:
/* emulated PLLs locked instantly? */
return NV_PRAMDAC_PLL_TEST_COUNTER_VPLL2_LOCK
| NV_PRAMDAC_PLL_TEST_COUNTER_NVPLL_LOCK
| NV_PRAMDAC_PLL_TEST_COUNTER_MPLL_LOCK
| NV_PRAMDAC_PLL_TEST_COUNTER_VPLL_LOCK;
break;
default:
EmuWarning("EmuNV2A_PRAMDAC_Read32: Unknown Read Address %08X", addr);
}
@ -309,6 +409,13 @@ uint32_t EmuNV2A_Read32(uint32_t addr)
void EmuNV2A_PMC_Write32(uint32_t addr, uint32_t value)
{
switch (addr) {
case NV_PMC_INTR_0: pmc.pending_interrupts &= ~value;
update_irq();
break;
case NV_PMC_INTR_EN_0:
pmc.enabled_interrupts = value;
update_irq();
break;
default:
EmuWarning("EmuNV2A_PMC_Write32: Unknown Write Address %08X (value %08X)", addr, value);
}
@ -366,6 +473,23 @@ void EmuNV2A_PCOUNTER_Write32(uint32_t addr, uint32_t value)
void EmuNV2A_PTIMER_Write32(uint32_t addr, uint32_t value)
{
switch (addr) {
case NV_PTIMER_INTR_0:
ptimer.pending_interrupts &= ~value;
update_irq();
break;
case NV_PTIMER_INTR_EN_0:
ptimer.enabled_interrupts = value;
update_irq();
break;
case NV_PTIMER_DENOMINATOR:
ptimer.denominator = value;
break;
case NV_PTIMER_NUMERATOR:
ptimer.numerator = value;
break;
case NV_PTIMER_ALARM_0:
ptimer.alarm_time = value;
break;
default:
EmuWarning("EmuNV2A_PTIMER_Write32: Unknown Write Address %08X (value %08X)", addr, value);
}
@ -407,7 +531,7 @@ void EmuNV2A_PFB_Write32(uint32_t addr, uint32_t value)
{
switch (addr) {
default:
EmuWarning("EmuNV2A_PFB_Write32: Unknown Write Address %08X (value %08X)", addr, value);
pfb.regs[addr] = value;
}
}
@ -430,6 +554,16 @@ void EmuNV2A_PGRAPH_Write32(uint32_t addr, uint32_t value)
void EmuNV2A_PCRTC_Write32(uint32_t addr, uint32_t value)
{
switch (addr) {
case NV_PCRTC_INTR_0:
pcrtc.pending_interrupts &= ~value;
update_irq();
break;
case NV_PCRTC_INTR_EN_0:
pcrtc.enabled_interrupts = value;
update_irq();
break;
case NV_PCRTC_START: pcrtc.start = value &= 0x07FFFFFF;
break;
default:
EmuWarning("EmuNV2A_PCRTC_Write32: Unknown Write Address %08X (value %08X)", addr, value);
}