diff --git a/src/CxbxKrnl/EmuNV2A.cpp b/src/CxbxKrnl/EmuNV2A.cpp index 016a829a9..e82641c34 100644 --- a/src/CxbxKrnl/EmuNV2A.cpp +++ b/src/CxbxKrnl/EmuNV2A.cpp @@ -28,6 +28,11 @@ // * // * (c) 2002-2003 Aaron Robinson // * (c) 2016 Luke Usher +// * +// * 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,11 +301,27 @@ uint32_t EmuNV2A_PRMCIO_Read32(uint32_t addr) uint32_t EmuNV2A_PRAMDAC_Read32(uint32_t addr) { - switch (addr) { - default: - EmuWarning("EmuNV2A_PRAMDAC_Read32: Unknown Read Address %08X", 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); } - + return 0; } @@ -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); } @@ -406,8 +530,8 @@ void EmuNV2A_PRMVIO_Write32(uint32_t addr, uint32_t value) 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); + default: + 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); }