Began porting NV2A emulation from XQEMU.
This commit is contained in:
parent
d424f0b004
commit
588aa5745b
|
@ -28,6 +28,11 @@
|
||||||
// *
|
// *
|
||||||
// * (c) 2002-2003 Aaron Robinson <caustik@caustik.com>
|
// * (c) 2002-2003 Aaron Robinson <caustik@caustik.com>
|
||||||
// * (c) 2016 Luke Usher <luke.usher@outlook.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
|
// * All rights reserved
|
||||||
// *
|
// *
|
||||||
// ******************************************************************
|
// ******************************************************************
|
||||||
|
@ -41,9 +46,80 @@
|
||||||
#include "EmuNV2A.h"
|
#include "EmuNV2A.h"
|
||||||
#include "nv2a_int.h" // from https://github.com/espes/xqemu/tree/xbox/hw/xbox
|
#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)
|
uint32_t EmuNV2A_PMC_Read32(uint32_t addr)
|
||||||
{
|
{
|
||||||
switch (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:
|
default:
|
||||||
EmuWarning("EmuNV2A_PMC_Read32: Unknown Read Address %08X", addr);
|
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:
|
case NV_PBUS_PCI_NV_0:
|
||||||
return 0x10de; // PCI_VENDOR_ID_NVIDIA
|
return 0x10de; // PCI_VENDOR_ID_NVIDIA
|
||||||
case NV_PBUS_PCI_NV_2:
|
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:
|
default:
|
||||||
EmuWarning("EmuNV2A_PBUS_Read32: Unknown Read Address %08X", addr);
|
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)
|
uint32_t EmuNV2A_PVIDEO_Read32(uint32_t addr)
|
||||||
{
|
{
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
|
case NV_PVIDEO_STOP:
|
||||||
|
return 0;
|
||||||
default:
|
default:
|
||||||
EmuWarning("EmuNV2A_PVIDEO_Read32: Unknown Read Address %08X", addr);
|
return pvideo.regs[addr];
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -198,6 +276,12 @@ uint32_t EmuNV2A_PGRAPH_Read32(uint32_t addr)
|
||||||
uint32_t EmuNV2A_PCRTC_Read32(uint32_t addr)
|
uint32_t EmuNV2A_PCRTC_Read32(uint32_t addr)
|
||||||
{
|
{
|
||||||
switch (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:
|
default:
|
||||||
EmuWarning("EmuNV2A_PCRTC_Read32: Unknown Read Address %08X", addr);
|
EmuWarning("EmuNV2A_PCRTC_Read32: Unknown Read Address %08X", addr);
|
||||||
}
|
}
|
||||||
|
@ -217,11 +301,27 @@ uint32_t EmuNV2A_PRMCIO_Read32(uint32_t addr)
|
||||||
|
|
||||||
uint32_t EmuNV2A_PRAMDAC_Read32(uint32_t addr)
|
uint32_t EmuNV2A_PRAMDAC_Read32(uint32_t addr)
|
||||||
{
|
{
|
||||||
switch (addr) {
|
switch (addr & 3) {
|
||||||
default:
|
case NV_PRAMDAC_NVPLL_COEFF:
|
||||||
EmuWarning("EmuNV2A_PRAMDAC_Read32: Unknown Read Address %08X", addr);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,6 +409,13 @@ uint32_t EmuNV2A_Read32(uint32_t addr)
|
||||||
void EmuNV2A_PMC_Write32(uint32_t addr, uint32_t value)
|
void EmuNV2A_PMC_Write32(uint32_t addr, uint32_t value)
|
||||||
{
|
{
|
||||||
switch (addr) {
|
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:
|
default:
|
||||||
EmuWarning("EmuNV2A_PMC_Write32: Unknown Write Address %08X (value %08X)", addr, value);
|
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)
|
void EmuNV2A_PTIMER_Write32(uint32_t addr, uint32_t value)
|
||||||
{
|
{
|
||||||
switch (addr) {
|
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:
|
default:
|
||||||
EmuWarning("EmuNV2A_PTIMER_Write32: Unknown Write Address %08X (value %08X)", addr, value);
|
EmuWarning("EmuNV2A_PTIMER_Write32: Unknown Write Address %08X (value %08X)", addr, value);
|
||||||
}
|
}
|
||||||
|
@ -406,8 +530,8 @@ void EmuNV2A_PRMVIO_Write32(uint32_t addr, uint32_t value)
|
||||||
void EmuNV2A_PFB_Write32(uint32_t addr, uint32_t value)
|
void EmuNV2A_PFB_Write32(uint32_t addr, uint32_t value)
|
||||||
{
|
{
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
default:
|
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)
|
void EmuNV2A_PCRTC_Write32(uint32_t addr, uint32_t value)
|
||||||
{
|
{
|
||||||
switch (addr) {
|
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:
|
default:
|
||||||
EmuWarning("EmuNV2A_PCRTC_Write32: Unknown Write Address %08X (value %08X)", addr, value);
|
EmuWarning("EmuNV2A_PCRTC_Write32: Unknown Write Address %08X (value %08X)", addr, value);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue