Refactored LLE X86 and NV2A

Completed operand decoding
Completed opcode ADD
Redirected 8 and 16 bit memory accesses to 32 bit
EmuX86 logging fixes and cleanup
Partiall support for misaligned memory accesses
NV2A macro cleanup
Clearer NV2A logging
Generic read/write on most NV2A components
This commit is contained in:
PatrickvL 2017-04-07 18:34:03 +02:00
parent 659b5f992b
commit 80d9d528f3
3 changed files with 373 additions and 309 deletions

View File

@ -179,7 +179,7 @@ XBSYSAPI EXPORTNUM(168) xboxkrnl::PVOID NTAPI xboxkrnl::MmClaimGpuInstanceMemory
*NumberOfPaddingBytes = MI_CONVERT_PFN_TO_PHYSICAL(MM_64M_PHYSICAL_PAGE) -
MI_CONVERT_PFN_TO_PHYSICAL(MM_INSTANCE_PHYSICAL_PAGE + MM_INSTANCE_PAGE_COUNT);
EmuWarning("*NumberOfPaddingBytes = 0x%08X", *NumberOfPaddingBytes);
DbgPrintf("MmClaimGpuInstanceMemory : *NumberOfPaddingBytes = 0x%08X\n", *NumberOfPaddingBytes);
if (NumberOfBytes != MAXULONG_PTR)
{

View File

@ -157,6 +157,7 @@ struct {
struct {
uint32_t pending_interrupts;
uint32_t enabled_interrupts;
uint32_t regs[NV_PGRAPH_SIZE / sizeof(uint32_t)]; // TODO : union
} pgraph;
@ -203,11 +204,11 @@ static void update_irq()
if (pmc.pending_interrupts && pmc.enabled_interrupts) {
// TODO Raise IRQ
EmuWarning("EmuNV2A update_irq() : Raise IRQ Not Implemented");
EmuWarning("NV2A update_irq() : Raise IRQ Not Implemented");
}
else {
// TODO: Cancel IRQ
EmuWarning("EmuNV2A update_irq() : Cancel IRQ Not Implemented");
EmuWarning("NV2A update_irq() : Cancel IRQ Not Implemented");
}
}
@ -234,30 +235,30 @@ DEBUG_START(PMC)
DEBUG_END(PMC)
DEBUG_START(PBUS)
DEBUG_CASE_EX(NV_PBUS_PCI_NV_0, "_VENDOR_ID");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_0, ":VENDOR_ID");
DEBUG_CASE(NV_PBUS_PCI_NV_1);
DEBUG_CASE_EX(NV_PBUS_PCI_NV_2, "_REVISION_ID");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_3, "_LATENCY_TIMER");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_2, ":REVISION_ID");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_3, ":LATENCY_TIMER");
DEBUG_CASE(NV_PBUS_PCI_NV_4);
DEBUG_CASE(NV_PBUS_PCI_NV_5);
DEBUG_CASE(NV_PBUS_PCI_NV_6);
DEBUG_CASE(NV_PBUS_PCI_NV_7);
DEBUG_CASE_EX(NV_PBUS_PCI_NV_11, "_SUBSYSTEM");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_12, "_ROM_BASE");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_13, "_CAP_PTR");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_14, "_RESERVED");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_11, ":SUBSYSTEM");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_12, ":ROM_BASE");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_13, ":CAP_PTR");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_14, ":RESERVED");
DEBUG_CASE(NV_PBUS_PCI_NV_15);
DEBUG_CASE_EX(NV_PBUS_PCI_NV_16, "_SUBSYSTEM");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_16, ":SUBSYSTEM");
DEBUG_CASE(NV_PBUS_PCI_NV_17);
DEBUG_CASE_EX(NV_PBUS_PCI_NV_18, "_AGP_STATUS");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_19, "_AGP_COMMAND");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_20, "_ROM_SHADOW");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_21, "_VGA");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_22, "_SCRATCH");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_23, "_DT_TIMEOUT");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_24, "_PME");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_25, "_POWER_STATE");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_26, "_RESERVED");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_18, ":AGP_STATUS");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_19, ":AGP_COMMAND");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_20, ":ROM_SHADOW");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_21, ":VGA");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_22, ":SCRATCH");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_23, ":DT_TIMEOUT");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_24, ":PME");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_25, ":POWER_STATE");
DEBUG_CASE_EX(NV_PBUS_PCI_NV_26, ":RESERVED");
DEBUG_END(PBUS)
DEBUG_START(PFIFO)
@ -511,23 +512,25 @@ DEBUG_END(USER)
#define DEBUG_READ32(DEV) DbgPrintf("EmuX86_Read32 NV2A_" #DEV "(0x%08X) = 0x%08X [Handled, %s]\n", addr, result, DebugNV_##DEV##(addr));
#define DEBUG_READ32_UNHANDLED(DEV) DbgPrintf("EmuX86_Read32 NV2A_" #DEV "(0x%08X) = 0x%08X [Unhandled, %s]\n", addr, result, DebugNV_##DEV##(addr));
#define DEBUG_READ32(DEV) DbgPrintf("EmuX86 Read32 NV2A " #DEV "(0x%08X) = 0x%08X [Handled, %s]\n", addr, result, DebugNV_##DEV##(addr))
#define DEBUG_READ32_UNHANDLED(DEV) { DbgPrintf("EmuX86 Read32 NV2A " #DEV "(0x%08X) = 0x%08X [Unhandled, %s]\n", addr, result, DebugNV_##DEV##(addr)); return result; }
#define DEBUG_WRITE32(DEV) DbgPrintf("EmuX86_Write32 NV2A_" #DEV "(0x%08X, 0x%08X) [Handled, %s]\n", addr, value, DebugNV_##DEV##(addr));
#define DEBUG_WRITE32_UNHANDLED(DEV) DbgPrintf("EmuX86_Write32 NV2A_" #DEV "(0x%08X, 0x%08X) [Unhandled, %s]\n", addr, value, DebugNV_##DEV##(addr));
#define DEBUG_WRITE32(DEV) DbgPrintf("EmuX86 Write32 NV2A " #DEV "(0x%08X, 0x%08X) [Handled, %s]\n", addr, value, DebugNV_##DEV##(addr))
#define DEBUG_WRITE32_UNHANDLED(DEV) { DbgPrintf("EmuX86 Write32 NV2A " #DEV "(0x%08X, 0x%08X) [Unhandled, %s]\n", addr, value, DebugNV_##DEV##(addr)); return; }
#define DEVICE_READ32(DEV) uint32_t EmuNV2A_##DEV##_Read32(xbaddr addr)
#define DEVICE_READ32_SWITCH(addr) uint32_t result = 0; switch (addr)
#define DEVICE_READ32_SWITCH() uint32_t result = 0; switch (addr)
#define DEVICE_READ32_REG(dev) result = dev.regs[addr / sizeof(uint32_t)]
#define DEVICE_READ32_END(DEV) DEBUG_READ32(DEV); return result
#define DEVICE_WRITE32(DEV) void EmuNV2A_##DEV##_Write32(xbaddr addr, uint32_t value)
#define DEVICE_WRITE32_SWITCH(DEV, addr) DEBUG_WRITE32(DEV); switch (addr)
#define DEVICE_WRITE32_REG(dev) dev.regs[addr / sizeof(uint32_t)] = value
#define DEVICE_WRITE32_END(DEV) DEBUG_WRITE32(DEV)
DEVICE_READ32(PMC)
{
DEVICE_READ32_SWITCH(addr) {
DEVICE_READ32_SWITCH() {
case NV_PMC_BOOT_0: // chipset and stepping: NV2A, A02, Rev 0
result = 0x02A000A2;
break;
@ -541,7 +544,7 @@ DEVICE_READ32(PMC)
result = NV20_REG_BASE_KERNEL;
break;
default:
DEBUG_READ32_UNHANDLED(PMC);
DEVICE_READ32_REG(pmc); // Was : DEBUG_READ32_UNHANDLED(PMC);
}
DEVICE_READ32_END(PMC);
@ -549,7 +552,7 @@ DEVICE_READ32(PMC)
DEVICE_WRITE32(PMC)
{
DEVICE_WRITE32_SWITCH(PMC, addr) {
switch(addr) {
case NV_PMC_INTR_0:
pmc.pending_interrupts &= ~value;
update_irq();
@ -560,14 +563,16 @@ DEVICE_WRITE32(PMC)
break;
default:
DEBUG_WRITE32_UNHANDLED(PMC);
DEVICE_WRITE32_REG(pmc); // Was : DEBUG_WRITE32_UNHANDLED(PMC);
}
DEVICE_WRITE32_END(PMC);
}
DEVICE_READ32(PBUS)
{
DEVICE_READ32_SWITCH(addr) {
DEVICE_READ32_SWITCH() {
case NV_PBUS_PCI_NV_0:
result = 0x10de; // PCI_VENDOR_ID_NVIDIA (?where to return PCI_DEVICE_ID_NVIDIA_NV2A = 0x01b7)
@ -580,7 +585,7 @@ DEVICE_READ32(PBUS)
break;
default:
DEBUG_READ32_UNHANDLED(PBUS);
DEBUG_READ32_UNHANDLED(PBUS); // TODO : DEVICE_READ32_REG(pbus);
}
DEVICE_READ32_END(PBUS);
@ -588,23 +593,27 @@ DEVICE_READ32(PBUS)
DEVICE_WRITE32(PBUS)
{
DEVICE_WRITE32_SWITCH(PBUS, addr) {
// TODO : Handle write on NV_PBUS_PCI_NV_1 with 1 (NV_PBUS_PCI_NV_1_IO_SPACE_ENABLED) + 4 (NV_PBUS_PCI_NV_1_BUS_MASTER_ENABLED)
switch(addr) {
case NV_PBUS_PCI_NV_1:
// TODO : Handle write on NV_PBUS_PCI_NV_1 with 1 (NV_PBUS_PCI_NV_1_IO_SPACE_ENABLED) + 4 (NV_PBUS_PCI_NV_1_BUS_MASTER_ENABLED)
break;
default:
DEBUG_WRITE32_UNHANDLED(PBUS);
DEBUG_WRITE32_UNHANDLED(PBUS); // TODO : DEVICE_WRITE32_REG(pbus);
}
DEVICE_WRITE32_END(PBUS);
}
DEVICE_READ32(PFIFO)
{
DEVICE_READ32_SWITCH(addr) {
DEVICE_READ32_SWITCH() {
case NV_PFIFO_RAMHT:
result = 0x03000100; // = NV_PFIFO_RAMHT_SIZE_4K | NV_PFIFO_RAMHT_BASE_ADDRESS(NumberOfPaddingBytes >> 12) | NV_PFIFO_RAMHT_SEARCH_128
case NV_PFIFO_RAMFC:
result = 0x00890110; // = ? | NV_PFIFO_RAMFC_SIZE_2K | ?
default:
DEBUG_READ32_UNHANDLED(PFIFO);
default:
DEVICE_READ32_REG(pfifo); // Was : DEBUG_READ32_UNHANDLED(PFIFO);
}
DEVICE_READ32_END(PFIFO);
@ -612,18 +621,20 @@ DEVICE_READ32(PFIFO)
DEVICE_WRITE32(PFIFO)
{
DEVICE_WRITE32_SWITCH(PFIFO, addr) {
switch(addr) {
default:
DEBUG_WRITE32_UNHANDLED(PFIFO);
DEVICE_WRITE32_REG(pfifo); // Was : DEBUG_WRITE32_UNHANDLED(PFIFO);
}
DEVICE_WRITE32_END(PFIFO);
}
DEVICE_READ32(PRMA)
{
DEVICE_READ32_SWITCH(addr) {
default:
DEBUG_READ32_UNHANDLED(PRMA);
DEVICE_READ32_SWITCH() {
default:
DEBUG_READ32_UNHANDLED(PRMA); // TODO : DEVICE_READ32_REG(prma);
}
DEVICE_READ32_END(PRMA);
@ -631,22 +642,24 @@ DEVICE_READ32(PRMA)
DEVICE_WRITE32(PRMA)
{
DEVICE_WRITE32_SWITCH(PRMA, addr) {
switch(addr) {
default:
DEBUG_WRITE32_UNHANDLED(PRMA);
DEBUG_WRITE32_UNHANDLED(PRMA); // TODO : DEVICE_WRITE32_REG(prma);
}
DEVICE_WRITE32_END(PRMA);
}
DEVICE_READ32(PVIDEO)
{
DEVICE_READ32_SWITCH(addr) {
DEVICE_READ32_SWITCH() {
case NV_PVIDEO_STOP:
result = 0;
break;
default:
result = pvideo.regs[addr];
DEVICE_READ32_REG(pvideo);
}
DEVICE_READ32_END(PVIDEO);
@ -654,17 +667,19 @@ DEVICE_READ32(PVIDEO)
DEVICE_WRITE32(PVIDEO)
{
DEVICE_WRITE32_SWITCH(PVIDEO, addr) {
switch (addr) {
default:
pvideo.regs[addr] = value;
DEVICE_WRITE32_REG(pvideo);
}
DEVICE_WRITE32_END(PVIDEO);
}
DEVICE_READ32(PCOUNTER)
{
DEVICE_READ32_SWITCH(addr) {
default:
DEBUG_READ32_UNHANDLED(PCOUNTER);
DEVICE_READ32_SWITCH() {
default:
DEBUG_READ32_UNHANDLED(PCOUNTER); // TODO : DEVICE_READ32_REG(pcounter);
}
DEVICE_READ32_END(PCOUNTER);
@ -672,16 +687,18 @@ DEVICE_READ32(PCOUNTER)
DEVICE_WRITE32(PCOUNTER)
{
DEVICE_WRITE32_SWITCH(PCOUNTER, addr) {
default:
DEBUG_WRITE32_UNHANDLED(PCOUNTER);
switch (addr) {
default:
DEBUG_WRITE32_UNHANDLED(PCOUNTER); // TODO : DEVICE_WRITE32_REG(pcounter);
}
DEVICE_WRITE32_END(PCOUNTER);
}
DEVICE_READ32(PTIMER)
{
DEVICE_READ32_SWITCH(addr) {
DEVICE_READ32_SWITCH() {
case NV_PTIMER_DENOMINATOR:
result = ptimer.denominator;
@ -693,7 +710,7 @@ DEVICE_READ32(PTIMER)
result = ptimer.alarm_time;
break;
default:
DEBUG_READ32_UNHANDLED(PTIMER);
DEVICE_READ32_REG(ptimer); // Was : DEBUG_READ32_UNHANDLED(PTIMER);
}
DEVICE_READ32_END(PTIMER);
@ -702,7 +719,7 @@ DEVICE_READ32(PTIMER)
DEVICE_WRITE32(PTIMER)
{
DEVICE_WRITE32_SWITCH(PTIMER, addr) {
switch (addr) {
case NV_PTIMER_INTR_0:
ptimer.pending_interrupts &= ~value;
@ -723,16 +740,18 @@ DEVICE_WRITE32(PTIMER)
break;
default:
DEBUG_WRITE32_UNHANDLED(PTIMER);
DEVICE_WRITE32_REG(ptimer); // Was : DEBUG_WRITE32_UNHANDLED(PTIMER);
}
DEVICE_WRITE32_END(PTIMER);
}
DEVICE_READ32(PVPE)
{
DEVICE_READ32_SWITCH(addr) {
default:
DEBUG_READ32_UNHANDLED(PVPE);
DEVICE_READ32_SWITCH() {
default:
DEBUG_READ32_UNHANDLED(PVPE); // TODO : DEVICE_READ32_REG(pvpe);
}
DEVICE_READ32_END(PVPE);
@ -741,18 +760,20 @@ DEVICE_READ32(PVPE)
DEVICE_WRITE32(PVPE)
{
DEVICE_WRITE32_SWITCH(PVPE, addr) {
default:
DEBUG_WRITE32_UNHANDLED(PVPE);
switch (addr) {
default:
DEBUG_WRITE32_UNHANDLED(PVPE); // TODO : DEVICE_WRITE32_REG(pvpe);
}
DEVICE_WRITE32_END(PVPE);
}
DEVICE_READ32(PTV)
{
DEVICE_READ32_SWITCH(addr) {
default:
DEBUG_READ32_UNHANDLED(PTV);
DEVICE_READ32_SWITCH() {
default:
DEBUG_READ32_UNHANDLED(PTV); // TODO : DEVICE_READ32_REG(ptv);
}
DEVICE_READ32_END(PTV);
@ -760,18 +781,20 @@ DEVICE_READ32(PTV)
DEVICE_WRITE32(PTV)
{
DEVICE_WRITE32_SWITCH(PTV, addr) {
default:
DEBUG_WRITE32_UNHANDLED(PTV);
switch (addr) {
default:
DEBUG_WRITE32_UNHANDLED(PTV); // TODO : DEVICE_WRITE32_REG(ptv);
}
DEVICE_WRITE32_END(PTV);
}
DEVICE_READ32(PRMFB)
{
DEVICE_READ32_SWITCH(addr) {
default:
DEBUG_READ32_UNHANDLED(PRMFB);
DEVICE_READ32_SWITCH() {
default:
DEBUG_READ32_UNHANDLED(PRMFB); // TODO : DEVICE_READ32_REG(prmfb);
}
DEVICE_READ32_END(PRMFB);
@ -779,18 +802,20 @@ DEVICE_READ32(PRMFB)
DEVICE_WRITE32(PRMFB)
{
DEVICE_WRITE32_SWITCH(PRMFB, addr) {
default:
DEBUG_WRITE32_UNHANDLED(PRMFB);
switch (addr) {
default:
DEBUG_WRITE32_UNHANDLED(PRMFB); // TODO : DEVICE_WRITE32_REG(prmfb);
}
DEVICE_WRITE32_END(PRMFB);
}
DEVICE_READ32(PRMVIO)
{
DEVICE_READ32_SWITCH(addr) {
default:
DEBUG_READ32_UNHANDLED(PRMVIO);
DEVICE_READ32_SWITCH() {
default:
DEBUG_READ32_UNHANDLED(PRMVIO); // TODO : DEVICE_READ32_REG(prmvio);
}
DEVICE_READ32_END(PRMVIO);
@ -798,20 +823,22 @@ DEVICE_READ32(PRMVIO)
DEVICE_WRITE32(PRMVIO)
{
DEVICE_WRITE32_SWITCH(PRMVIO, addr) {
default:
DEBUG_WRITE32_UNHANDLED(PRMVIO);
switch (addr) {
default:
DEBUG_WRITE32_UNHANDLED(PRMVIO); // TODO : DEVICE_WRITE32_REG(prmvio);
}
DEVICE_WRITE32_END(PRMVIO);
}
DEVICE_READ32(PFB)
{
DEVICE_READ32_SWITCH(addr) {
DEVICE_READ32_SWITCH() {
case NV_PFB_CFG0:
result = 3; // = NV_PFB_CFG0_PART_4
default:
result = pfb.regs[addr];
DEVICE_READ32_REG(pfb);
}
DEVICE_READ32_END(PFB);
@ -819,17 +846,19 @@ DEVICE_READ32(PFB)
DEVICE_WRITE32(PFB)
{
DEVICE_WRITE32_SWITCH(PFB, addr) {
switch (addr) {
default:
pfb.regs[addr] = value;
DEVICE_WRITE32_REG(pfb);
}
DEVICE_WRITE32_END(PFB);
}
DEVICE_READ32(PSTRAPS)
{
DEVICE_READ32_SWITCH(addr) {
default:
DEVICE_READ32_SWITCH() {
default:
DEBUG_READ32_UNHANDLED(PSTRAPS);
}
@ -838,17 +867,19 @@ DEVICE_READ32(PSTRAPS)
DEVICE_WRITE32(PSTRAPS)
{
DEVICE_WRITE32_SWITCH(PSTRAPS, addr) {
default:
switch (addr) {
default:
DEBUG_WRITE32_UNHANDLED(PSTRAPS);
}
DEVICE_WRITE32_END(PSTRAPS);
}
DEVICE_READ32(PGRAPH)
{
DEVICE_READ32_SWITCH(addr) {
default:
DEVICE_READ32_SWITCH() {
default:
DEBUG_READ32_UNHANDLED(PGRAPH);
}
@ -857,7 +888,7 @@ DEVICE_READ32(PGRAPH)
DEVICE_WRITE32(PGRAPH)
{
DEVICE_WRITE32_SWITCH(PGRAPH, addr) {
switch (addr) {
case NV_PGRAPH_INTR:
pgraph.pending_interrupts &= ~value;
update_irq();
@ -867,14 +898,16 @@ DEVICE_WRITE32(PGRAPH)
update_irq();
break;
default:
DEBUG_WRITE32_UNHANDLED(PGRAPH);
DEVICE_WRITE32_REG(pgraph); // Was : DEBUG_WRITE32_UNHANDLED(PGRAPH);
}
DEVICE_WRITE32_END(PGRAPH);
}
DEVICE_READ32(PCRTC)
{
DEVICE_READ32_SWITCH(addr) {
DEVICE_READ32_SWITCH() {
case NV_PCRTC_INTR_0:
result = pcrtc.pending_interrupts;
@ -886,7 +919,7 @@ DEVICE_READ32(PCRTC)
result = pcrtc.start;
break;
default:
DEBUG_READ32_UNHANDLED(PCRTC);
DEVICE_READ32_REG(pcrtc); // Was : DEBUG_READ32_UNHANDLED(PCRTC);
}
DEVICE_READ32_END(PCRTC);
@ -894,7 +927,7 @@ DEVICE_READ32(PCRTC)
DEVICE_WRITE32(PCRTC)
{
DEVICE_WRITE32_SWITCH(PCRTC, addr) {
switch (addr) {
case NV_PCRTC_INTR_0:
pcrtc.pending_interrupts &= ~value;
@ -909,15 +942,17 @@ DEVICE_WRITE32(PCRTC)
break;
default:
DEBUG_WRITE32_UNHANDLED(PCRTC);
DEVICE_WRITE32_REG(pcrtc); // Was : DEBUG_WRITE32_UNHANDLED(PCRTC);
}
DEVICE_WRITE32_END(PCRTC);
}
DEVICE_READ32(PRMCIO)
{
DEVICE_READ32_SWITCH(addr) {
default:
DEVICE_READ32_SWITCH() {
default:
DEBUG_READ32_UNHANDLED(PRMCIO);
}
@ -926,16 +961,18 @@ DEVICE_READ32(PRMCIO)
DEVICE_WRITE32(PRMCIO)
{
DEVICE_WRITE32_SWITCH(PRMCIO, addr) {
default:
DEBUG_WRITE32_UNHANDLED(PRMCIO);
switch (addr) {
default:
DEBUG_WRITE32_UNHANDLED(PRMCIO); // TODO : DEVICE_WRITE32_REG(prmcio);
}
DEVICE_WRITE32_END(PRMCIO);
}
DEVICE_READ32(PRAMDAC)
{
DEVICE_READ32_SWITCH(addr) {
DEVICE_READ32_SWITCH() {
case NV_PRAMDAC_NVPLL_COEFF:
result = pramdac.core_clock_coeff;
@ -955,7 +992,7 @@ DEVICE_READ32(PRAMDAC)
break;
default:
DEBUG_READ32_UNHANDLED(PRAMDAC);
DEVICE_READ32_REG(pramdac); // Was : DEBUG_READ32_UNHANDLED(PRAMDAC);
}
DEVICE_READ32_END(PRAMDAC);
@ -963,7 +1000,7 @@ DEVICE_READ32(PRAMDAC)
DEVICE_WRITE32(PRAMDAC)
{
DEVICE_WRITE32_SWITCH(PRAMDAC, addr) {
switch (addr) {
case NV_PRAMDAC_NVPLL_COEFF:
pramdac.core_clock_coeff = value;
@ -976,15 +1013,17 @@ DEVICE_WRITE32(PRAMDAC)
break;
default:
DEBUG_WRITE32_UNHANDLED(PRAMDAC);
DEVICE_WRITE32_REG(pramdac); // Was : DEBUG_WRITE32_UNHANDLED(PRAMDAC);
}
DEVICE_WRITE32_END(PRAMDAC);
}
DEVICE_READ32(PRMDIO)
{
DEVICE_READ32_SWITCH(addr) {
default:
DEVICE_READ32_SWITCH() {
default:
DEBUG_READ32_UNHANDLED(PRMDIO);
}
@ -993,18 +1032,20 @@ DEVICE_READ32(PRMDIO)
DEVICE_WRITE32(PRMDIO)
{
DEVICE_WRITE32_SWITCH(PRMDIO, addr) {
default:
switch (addr) {
default:
DEBUG_WRITE32_UNHANDLED(PRMDIO);
}
DEVICE_WRITE32_END(PRMDIO);
}
DEVICE_READ32(PRAMIN)
{
DEVICE_READ32_SWITCH(addr) {
default:
result = pramin.regs[addr];
DEVICE_READ32_SWITCH() {
default:
DEVICE_READ32_REG(pramin);
}
DEVICE_READ32_END(PRAMIN);
@ -1012,17 +1053,19 @@ DEVICE_READ32(PRAMIN)
DEVICE_WRITE32(PRAMIN)
{
DEVICE_WRITE32_SWITCH(PRAMIN, addr) {
default:
pramin.regs[addr] = value;
}
switch (addr) {
default:
DEVICE_WRITE32_REG(pramin);
/ }
DEVICE_WRITE32_END(PRAMIN);
}
DEVICE_READ32(USER)
{
DEVICE_READ32_SWITCH(addr) {
default:
DEVICE_READ32_SWITCH() {
default:
DEBUG_READ32_UNHANDLED(USER);
}
@ -1031,10 +1074,12 @@ DEVICE_READ32(USER)
DEVICE_WRITE32(USER)
{
DEVICE_WRITE32_SWITCH(USER, addr) {
default:
switch (addr) {
default:
DEBUG_WRITE32_UNHANDLED(USER);
}
DEVICE_WRITE32_END(USER);
}

View File

@ -51,6 +51,8 @@
#include "EmuNV2A.h"
#include "HLEIntercept.h" // for bLLE_GPU
#include <assert.h>
//
// Read & write handlers handlers for I/O
//
@ -130,86 +132,138 @@ void EmuX86_Mem_Write8(xbaddr addr, uint8_t value)
// Read & write handlers for memory-mapped hardware devices
//
uint32_t EmuX86_Read32(xbaddr addr)
uint32_t EmuX86_Read32Aligned(xbaddr addr)
{
// TODO : Should we assert ((addr & 3) == 0) here?
uint32_t value = 0;
assert((addr & 3) == 0);
uint32_t value;
if (addr >= NV2A_ADDR && addr < NV2A_ADDR + NV2A_SIZE) {
if (!bLLE_GPU) {
EmuWarning("EmuX86_Read32(0x%08X) Unexpected NV2A access, missing a HLE patch. " \
EmuWarning("EmuX86_Read32Aligned(0x%08X) Unexpected NV2A access, missing a HLE patch. " \
"Please notify https://github.com/Cxbx-Reloaded/Cxbx-Reloaded which title raised this!", addr);
} else
value = EmuNV2A_Read32(addr - NV2A_ADDR);
} else
if (g_bEmuException)
EmuWarning("EmuX86_Read32(0x%08X) [Unknown address]", addr);
else
}
// Access NV2A regardless weither HLE is disabled or not
value = EmuNV2A_Read32(addr - NV2A_ADDR);
// Note : EmuNV2A_Read32 does it's own logging
} else {
if (g_bEmuException) {
EmuWarning("EmuX86_Read32Aligned(0x%08X) [Unknown address]", addr);
value = 0;
} else {
// Outside EmuException, pass the memory-access through to normal memory :
value = EmuX86_Mem_Read32(addr);
}
DbgPrintf("EmuX86_Read32Aligned(0x%08X) = 0x%08X\n", addr, value);
}
return value;
}
uint32_t EmuX86_Read32(xbaddr addr)
{
uint32_t value;
if ((addr & 3) == 0)
value = EmuX86_Read32Aligned(addr);
else {
EmuWarning("EmuX86_Read32(0x%08X) [Unaligned unimplemented]", addr);
value = 0;
}
DbgPrintf("EmuX86_Read32(0x%08X) = 0x%04X", addr, value);
return value;
}
uint16_t EmuX86_Read16(xbaddr addr)
{
DbgPrintf("EmuX86_Read16(0x%08X) Forwarding to EmuX86_Read32...", addr);
uint16_t value;
if (addr & 2)
value = (uint16_t)(EmuX86_Read32(addr - 2) >> 16);
else
value = (uint16_t)EmuX86_Read32(addr);
DbgPrintf("EmuX86_Read16(0x%08X) Forwarding to EmuX86_Read32Aligned...\n", addr);
DbgPrintf("EmuX86_Read16(0x%08X) = 0x%04X", addr, value);
int shift = (addr & 3) * 8;
xbaddr aligned_addr = addr & ~3;
uint16_t value = (uint16_t)(EmuX86_Read32Aligned(aligned_addr) >> shift);
// Must the second byte be retrieved from the next DWORD?
if ((addr & 3) == 3)
value |= (uint16_t)((EmuX86_Read32Aligned(aligned_addr + 4) & 0xff) << 8);
DbgPrintf("EmuX86_Read16(0x%08X) = 0x%04X\n", addr, value);
return value;
}
uint8_t EmuX86_Read8(xbaddr addr)
{
DbgPrintf("EmuX86_Read8(0x%08X) Forwarding to EmuX86_Read16...", addr);
uint8_t value;
if (addr & 1)
value = (uint8_t)(EmuX86_Read16(addr - 1) >> 8);
else
value = (uint8_t)EmuX86_Read16(addr);
DbgPrintf("EmuX86_Read8(0x%08X) Forwarding to EmuX86_Read32Aligned...\n", addr);
DbgPrintf("EmuX86_Read8(0x%08X) = 0x%02X", addr, value);
int shift = (addr & 3) * 8;
xbaddr aligned_addr = addr & ~3;
uint8_t value = (uint8_t)(EmuX86_Read32Aligned(aligned_addr) >> shift);
DbgPrintf("EmuX86_Read8(0x%08X) = 0x%02X\n", addr, value);
return value;
}
void EmuX86_Write32(xbaddr addr, uint32_t value)
void EmuX86_Write32Aligned(xbaddr addr, uint32_t value)
{
// TODO : Should we assert ((addr & 3) == 0) here?
assert((addr & 3) == 0);
if (addr >= NV2A_ADDR && addr < NV2A_ADDR + NV2A_SIZE) {
if (!bLLE_GPU) {
EmuWarning("EmuX86_Write32(0x%08X, 0x%08X) Unexpected NV2A access, missing a HLE patch. " \
EmuWarning("EmuX86_Write32Aligned(0x%08X, 0x%08X) Unexpected NV2A access, missing a HLE patch. " \
"Please notify https://github.com/Cxbx-Reloaded/Cxbx-Reloaded which title raised this!", addr);
return;
}
// Access NV2A regardless weither HLE is disabled or not
EmuNV2A_Write32(addr - NV2A_ADDR, value);
// Note : EmuNV2A_Write32 does it's own logging
return;
}
if (g_bEmuException) {
EmuWarning("EmuX86_Write32(0x%08X, 0x%08X) [Unknown address]", addr, value);
EmuWarning("EmuX86_Write32Aligned(0x%08X, 0x%08X) [Unknown address]", addr, value);
return;
}
// Outside EmuException, pass the memory-access through to normal memory :
DbgPrintf("EmuX86_Write32Aligned(0x%08X, 0x%08X)\n", addr, value);
EmuX86_Mem_Write32(addr, value);
}
void EmuX86_Write32(xbaddr addr, uint32_t value)
{
if ((addr & 3) == 0) {
EmuX86_Write32Aligned(addr, value);
}
else
EmuWarning("EmuX86_Write32(0x%08X, 0x%08X) [Unaligned unimplemented]", addr, value);
}
void EmuX86_Write16(xbaddr addr, uint16_t value)
{
EmuWarning("EmuX86_Write16(0x%08X, 0x%04X) [Unknown address]", addr, value);
// TODO : If decided to do so, read32, mask value in, and forward to write32
DbgPrintf("EmuX86_Write16(0x%08X, 0x%04X) Forwarding to EmuX86_Read32Aligned+EmuX86_Write32Aligned\n", addr, value);
assert((addr & 1) == 0);
int shift = (addr & 2) * 16;
xbaddr aligned_addr = addr & ~3;
uint32_t aligned_value = EmuX86_Read32Aligned(aligned_addr);
uint32_t mask = 0xFFFF << shift;
// TODO : Must the second byte be written to the next DWORD?
EmuX86_Write32Aligned(aligned_addr, (aligned_value & ~mask) | (value << shift));
}
void EmuX86_Write8(xbaddr addr, uint8_t value)
{
EmuWarning("EmuX86_Write8(0x%08X, 0x%02X) [Unknown address]", addr, value);
// TODO : If decided to do so, read16, mask value in, and forward to write16
DbgPrintf("EmuX86_Write8(0x%08X, 0x%02X) Forwarding to EmuX86_Read32Aligned+EmuX86_Write32Aligned\n", addr, value);
int shift = (addr & 3) * 8;
xbaddr aligned_addr = addr & ~3;
uint32_t aligned_value = EmuX86_Read32Aligned(aligned_addr);
uint32_t mask = 0xFF << shift;
EmuX86_Write32Aligned(aligned_addr, (aligned_value & ~mask) | (value << shift));
}
int ContextRecordOffsetByRegisterType[/*_RegisterType*/R_DR7 + 1] = { 0 };
@ -380,196 +434,154 @@ xbaddr EmuX86_Distorm_O_MEM_Addr(LPEXCEPTION_POINTERS e, _DInst& info, int opera
return base + index + (uint32_t)info.disp;
}
void EmuX86_Addr_Read(xbaddr srcAddr, uint16_t size, OUT uint32_t *value)
{
switch (size) {
case 8:
*value = EmuX86_Read8(srcAddr);
return;
case 16:
*value = EmuX86_Read16(srcAddr);
return;
case 32:
*value = EmuX86_Read32(srcAddr);
}
}
void EmuX86_Addr_Write(xbaddr destAddr, uint16_t size, uint32_t value)
{
switch (size) {
case 8:
EmuX86_Write8(destAddr, value & 0xFF);
return;
case 16:
EmuX86_Write16(destAddr, value & 0xFFFF);
return;
case 32:
EmuX86_Write32(destAddr, value);
}
}
bool EmuX86_Operand_Read(LPEXCEPTION_POINTERS e, _DInst& info, int operand, OUT uint32_t *value)
xbaddr EmuX86_Operand_Addr(LPEXCEPTION_POINTERS e, _DInst& info, int operand, bool &is_internal_addr)
{
switch (info.ops[operand].type) {
case O_NONE:
{
// ignore operand
return true;
return (xbaddr)nullptr;
}
case O_REG:
is_internal_addr = true;
return (xbaddr)EmuX86_GetRegisterPointer(e, info.ops[operand].index);
{
void* regAddr = EmuX86_GetRegisterPointer(e, info.ops[operand].index);
if (regAddr == 0)
return false;
switch (info.ops[operand].size) {
case 8:
*value = *((uint8_t*)regAddr);
return true;
case 16:
*value = *((uint16_t*)regAddr);
return true;
case 32:
*value = *((uint32_t*)regAddr);
return true;
}
return false;
}
case O_IMM:
{
switch (info.ops[operand].size) {
case 8:
*value = info.imm.byte;
return true;
case 16:
*value = info.imm.word;
return true;
case 32:
*value = info.imm.dword;
return true;
}
return false;
is_internal_addr = true;
return (xbaddr)(&info.imm);
}
case O_IMM1:
{
// TODO
return false;
is_internal_addr = true;
return (xbaddr)(&info.imm.ex.i1);
}
case O_IMM2:
{
// TODO
return false;
is_internal_addr = true;
return (xbaddr)(&info.imm.ex.i2);
}
case O_DISP:
{
xbaddr srcAddr = (xbaddr)info.disp;
EmuX86_Addr_Read(srcAddr, info.ops[operand].size, value);
return true;
is_internal_addr = false;
return (xbaddr)info.disp;
}
case O_SMEM:
{
xbaddr srcAddr = EmuX86_Distorm_O_SMEM_Addr(e, info, operand);
EmuX86_Addr_Read(srcAddr, info.ops[operand].size, value);
return true;
is_internal_addr = false;
return EmuX86_Distorm_O_SMEM_Addr(e, info, operand);
}
case O_MEM:
{
xbaddr srcAddr = EmuX86_Distorm_O_MEM_Addr(e, info, operand);
EmuX86_Addr_Read(srcAddr, info.ops[operand].size, value);
return true;
is_internal_addr = false;
return EmuX86_Distorm_O_MEM_Addr(e, info, operand);
}
case O_PC:
{
// TODO
return false;
is_internal_addr = false;
return (xbaddr)INSTRUCTION_GET_TARGET(&info);
}
case O_PTR:
{
// TODO
return false;
is_internal_addr = false;
return (xbaddr)info.imm.ptr.off; // TODO : What about info.imm.ptr.seg ?
}
default:
return false;
return (xbaddr)nullptr;
}
return (xbaddr)nullptr;
}
bool EmuX86_Addr_Read(xbaddr srcAddr, bool is_internal_addr, uint16_t size, OUT uint32_t *value)
{
if (is_internal_addr)
{
switch (size) {
case 8:
*value = *((uint8_t*)srcAddr);
return true;
case 16:
*value = *((uint16_t*)srcAddr);
return true;
case 32:
*value = *((uint32_t*)srcAddr);
return true;
default:
return false;
}
}
else
{
switch (size) {
case 8:
*value = EmuX86_Read8(srcAddr);
return true;
case 16:
*value = EmuX86_Read16(srcAddr);
return true;
case 32:
*value = EmuX86_Read32(srcAddr);
return true;
default:
return false;
}
}
}
bool EmuX86_Addr_Write(xbaddr destAddr, bool is_internal_addr, uint16_t size, uint32_t value)
{
if (is_internal_addr)
{
switch (size) {
case 8:
*((uint8_t*)destAddr) = (uint8_t)value;
return true;
case 16:
*((uint16_t*)destAddr) = (uint16_t)value;
return true;
case 32:
*((uint32_t*)destAddr) = value;
return true;
default:
return false;
}
}
else
{
switch (size) {
case 8:
EmuX86_Write8(destAddr, value & 0xFF);
return true;
case 16:
EmuX86_Write16(destAddr, value & 0xFFFF);
return true;
case 32:
EmuX86_Write32(destAddr, value);
return true;
default:
return false;
}
}
}
bool EmuX86_Operand_Read(LPEXCEPTION_POINTERS e, _DInst& info, int operand, OUT uint32_t *value)
{
bool is_internal_addr;
xbaddr srcAddr = EmuX86_Operand_Addr(e, info, operand, OUT is_internal_addr);
if (srcAddr != (xbaddr)nullptr)
return EmuX86_Addr_Read(srcAddr, is_internal_addr, info.ops[operand].size, value);
return false;
}
bool EmuX86_Operand_Write(LPEXCEPTION_POINTERS e, _DInst& info, int operand, uint32_t value)
{
switch (info.ops[operand].type) {
case O_NONE:
{
// ignore operand
return true;
}
case O_REG:
{
void* regAddr = EmuX86_GetRegisterPointer(e, info.ops[operand].index);
if (regAddr == nullptr)
return false;
switch (info.ops[operand].size) {
case 8:
*((uint8_t*)regAddr) = (uint8_t)value;
return true;
case 16:
*((uint16_t*)regAddr) = (uint16_t)value;
return true;
case 32:
*((uint32_t*)regAddr) = value;
return true;
default:
return false;
}
return false;
}
case O_IMM:
{
// TODO
return false;
}
case O_IMM1:
{
// TODO
return false;
}
case O_IMM2:
{
// TODO
return false;
}
case O_DISP:
{
xbaddr destAddr = (xbaddr)info.disp;
EmuX86_Addr_Write(destAddr, info.ops[operand].size, value);
return true;
}
case O_SMEM:
{
xbaddr destAddr = EmuX86_Distorm_O_SMEM_Addr(e, info, operand);
EmuX86_Addr_Write(destAddr, info.ops[operand].size, value);
return true;
}
case O_MEM:
{
xbaddr destAddr = EmuX86_Distorm_O_MEM_Addr(e, info, operand);
EmuX86_Addr_Write(destAddr, info.ops[operand].size, value);
return true;
}
case O_PC:
{
// TODO
return false;
}
case O_PTR:
{
// TODO
return false;
}
default:
return false;
}
bool is_internal_addr;
xbaddr destAddr = EmuX86_Operand_Addr(e, info, operand, OUT is_internal_addr);
if (destAddr != (xbaddr)nullptr)
return EmuX86_Addr_Write(destAddr, is_internal_addr, info.ops[operand].size, value);
return false;
}
@ -582,9 +594,12 @@ bool EmuX86_Opcode_ADD(LPEXCEPTION_POINTERS e, _DInst& info)
return false;
// ADD reads and writes destination :
xbaddr addr;
// TODO : Implement EmuX86_Operand_Addr, then enable the following line :
// if (!EmuX86_Operand_Addr(e, info, 0, &addr))
bool is_internal_addr;
xbaddr addr = EmuX86_Operand_Addr(e, info, 0, OUT is_internal_addr);
if (addr == (xbaddr)nullptr)
return false;
if (is_internal_addr)
return false;
// TODO : Do this better
@ -776,6 +791,10 @@ bool EmuX86_DecodeException(LPEXCEPTION_POINTERS e)
unsigned int decodedInstructionsCount = 0;
_CodeInfo ci;
if (e->ContextRecord->Eip == 0x00023A8A)
// 00023A8A 03B2 28010000 add esi, [edx + $00000128]; CMiniport_SetDmaRange + 13E8
ci.code = (uint8_t*)e->ContextRecord->Eip;
else
ci.code = (uint8_t*)e->ContextRecord->Eip;
ci.codeLen = 20;
ci.codeOffset = 0;