Stub all NV2A engines

This commit is contained in:
StrikerX3 2019-12-08 16:07:40 -03:00
parent c49ed8dffa
commit 170558276b
41 changed files with 1162 additions and 30 deletions

View file

@ -0,0 +1,46 @@
// Abstract base class for NV2A engines
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
#pragma once
#include <cstdint>
#include <string>
#include "state.h"
namespace strikebox::nv2a {
// Abstract base class of all NV2A engines.
class NV2AEngine {
public:
NV2AEngine(const std::string name, const uint32_t offset, const uint32_t length, const NV2A& nv2a)
: m_name(name)
, m_offset(offset)
, m_length(length)
, m_offsetEnd(offset + length)
, m_nv2a(nv2a)
{}
virtual uint32_t Read(const uint32_t addr, const uint8_t size) = 0;
virtual void Write(const uint32_t addr, const uint32_t value, const uint8_t size) = 0;
const std::string GetName() const noexcept { return m_name; }
const uint32_t GetOffset() const noexcept { return m_offset; }
const uint32_t GetLength() const noexcept { return m_length; }
const bool Contains(uint32_t address) const noexcept { return address >= m_offset && address < m_offsetEnd; }
private:
const std::string m_name;
const uint32_t m_offset;
const uint32_t m_length;
const uint32_t m_offsetEnd; // m_offset + m_length, precomputed for speed
const NV2A& m_nv2a;
};
}

View file

@ -0,0 +1,57 @@
// StrikeBox NV2A emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
//
// NV2A is a custom GPU designed by Nvidia for the Original Xbox. Internally,
// the chip is split up into different engines that are mapped to distinct
// regions of the system memory allocated to the device:
//
// Engine Offset Length Description
// ----------------------------------------------------------------------------
// PMC 0x000000 0x1000 Master control
// PBUS 0x001000 0x1000 Bus control
// PFIFO 0x002000 0x2000 MMIO and DMA FIFO submission to PGRAPH (there's no VPE in NV2A)
// PRMA 0x007000 0x1000 Real mode BAR access
// PVIDEO 0x008000 0x1000 Video overlay
// PTIMER 0x009000 0x1000 Time measurement and time-based alarms
// PCOUNTER 0x00A000 0x1000 Performance monitoring counters
// PNVIO 0x0C0000 0x1000 VGA sequencer and graph controller registers
// PFB 0x100000 0x1000 Memory interface
// PSTRAPS 0x101000 0x1000 Straps readout
// PROM 0x300000 0x20000 ROM access window
// PGRAPH 0x400000 0x2000 2D/3D graphics engine
// PCRTC 0x600000 0x1000 CRTC controls
// PRMCIO 0x601000 0x1000 VGA CRTC and attribute controller registers
// PRAMDAC 0x680000 0x1000 RAMDAC, video overlay, cursor, and PLL control
// PRMDIO 0x681000 0x1000 VGA DAC registers
// PRAMIN 0x700000 0x100000 RAMIN access
// USER 0x800000 0x200000 PFIFO MMIO/DMA submission area
//
#pragma once
#include "state.h"
#include "engine.h"
#include "pmc.h"
#include "pbus.h"
#include "pfifo.h"
#include "prma.h"
#include "pvideo.h"
#include "ptimer.h"
#include "pcounter.h"
#include "pnvio.h"
#include "pfb.h"
#include "pstraps.h"
#include "prom.h"
#include "pgraph.h"
#include "pcrtc.h"
#include "prmcio.h"
#include "pramdac.h"
#include "prmdio.h"
#include "pramin.h"
#include "user.h"

View file

@ -0,0 +1,31 @@
// StrikeBox NV2A PBUS (Bus control) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
//
// [https://envytools.readthedocs.io/en/latest/hw/bus/pbus.html]
// "PBUS is present on all nvidia cards.
// In theory, it deals with "bus control". In practice, it accumulates all sort of junk nobody bothered to create a special area for.
// It is unaffected by any PMC.ENABLE bits."
//
// PBUS engine registers occupy the range 0x001000..0x001FFF.
#pragma once
#include "engine.h"
namespace strikebox::nv2a {
// NV2A bus control engine (PBUS)
class PBUS : public NV2AEngine {
public:
PBUS(const NV2A& nv2a) : NV2AEngine("PBUS", 0x001000, 0x1000, nv2a) {}
uint32_t Read(const uint32_t addr, const uint8_t size) override;
void Write(const uint32_t addr, const uint32_t value, const uint8_t size) override;
};
}

View file

@ -0,0 +1,33 @@
// StrikeBox NV2A PCOUNTER (Performance monitoring counters) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
//
// [https://envytools.readthedocs.io/en/latest/hw/pcounter/intro.html]
// "PCOUNTER is the card units that contains performance monitoring counters.
// [...]
// PCOUNTER is actually made of several identical hardware counter units, one for each so-called domain.
// Each PCOUNTER domain can potentially run on a different source clock, allowing one to monitor events in various clock domains.
// The PCOUNTER domains are mostly independent, but there's some limitted communication and shared circuitry among them."
//
// PCOUNTER engine registers occupy the range 0x00A000..0x00AFFF.
#pragma once
#include "engine.h"
namespace strikebox::nv2a {
// NV2A performance monitoring counters engine (PCOUNTER)
class PCOUNTER : public NV2AEngine {
public:
PCOUNTER(const NV2A& nv2a) : NV2AEngine("PCOUNTER", 0x00A000, 0x1000, nv2a) {}
uint32_t Read(const uint32_t addr, const uint8_t size) override;
void Write(const uint32_t addr, const uint32_t value, const uint8_t size) override;
};
}

View file

@ -0,0 +1,26 @@
// StrikeBox NV2A PCRTC (CRTC controls) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
//
// PCRTC engine registers occupy the range 0x600000..0x600FFF.
#pragma once
#include "engine.h"
namespace strikebox::nv2a {
// NV2A CRTC controls engine (PCRTC)
class PCRTC : public NV2AEngine {
public:
PCRTC(const NV2A& nv2a) : NV2AEngine("PCRTC", 0x600000, 0x1000, nv2a) {}
uint32_t Read(const uint32_t addr, const uint8_t size) override;
void Write(const uint32_t addr, const uint32_t value, const uint8_t size) override;
};
}

View file

@ -0,0 +1,26 @@
// StrikeBox NV2A PFB (Memory interface) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
//
// PFB engine registers occupy the range 0x100000..0x100FFF.
#pragma once
#include "engine.h"
namespace strikebox::nv2a {
// NV2A memory interface engine (PFB)
class PFB : public NV2AEngine {
public:
PFB(const NV2A& nv2a) : NV2AEngine("PFB", 0x100000, 0x1000, nv2a) {}
uint32_t Read(const uint32_t addr, const uint8_t size) override;
void Write(const uint32_t addr, const uint32_t value, const uint8_t size) override;
};
}

View file

@ -0,0 +1,32 @@
// StrikeBox NV2A PFIFO (MMIO and DMA FIFO submission to PGRAPH) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
//
// [https://envytools.readthedocs.io/en/latest/hw/fifo/intro.html]
// "Commands to most of the engines are sent through a special engine called PFIFO.
// PFIFO maintains multiple fully independent command queues, known as "channels" or "FIFO"s.
// Each channel is controlled through a "channel control area", which is a region of MMIO.
// PFIFO intercepts all accesses to that area and acts upon them."
//
// PFIFO engine registers occupy the range 0x002000..0x003FFF.
#pragma once
#include "engine.h"
namespace strikebox::nv2a {
// NV2A MMIO and DMA FIFO submission to PGRAPH engine (PFIFO)
class PFIFO : public NV2AEngine {
public:
PFIFO(const NV2A& nv2a) : NV2AEngine("PFIFO", 0x002000, 0x2000, nv2a) {}
uint32_t Read(const uint32_t addr, const uint8_t size) override;
void Write(const uint32_t addr, const uint32_t value, const uint8_t size) override;
};
}

View file

@ -0,0 +1,28 @@
// StrikeBox NV2A PGRAPH (2D/3D graphics engine) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
//
// PGRAPH is the main engine responsible for 2D/3D graphics command processing.
//
// PGRAPH engine registers occupy the range 0x400000..0x401FFF.
#pragma once
#include "engine.h"
namespace strikebox::nv2a {
// NV2A 2D/3D graphics engine (PGRAPH)
class PGRAPH : public NV2AEngine {
public:
PGRAPH(const NV2A& nv2a) : NV2AEngine("PGRAPH", 0x400000, 0x2000, nv2a) {}
uint32_t Read(const uint32_t addr, const uint8_t size) override;
void Write(const uint32_t addr, const uint32_t value, const uint8_t size) override;
};
}

View file

@ -0,0 +1,30 @@
// StrikeBox NV2A PMC (Master control) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
//
// [https://envytools.readthedocs.io/en/latest/hw/bus/pmc.html]
// "PMC is the "master control" engine of the card. Its purpose is to provide card identication,
// manage enable/disable bits of other engines, and handle top-level interrupt routing."
//
// PMC engine registers occupy the range 0x000000..0x000FFF.
#pragma once
#include "engine.h"
namespace strikebox::nv2a {
// NV2A master control engine (PMC)
class PMC : public NV2AEngine {
public:
PMC(const NV2A& nv2a) : NV2AEngine("PMC", 0x000000, 0x1000, nv2a) {}
uint32_t Read(const uint32_t addr, const uint8_t size) override;
void Write(const uint32_t addr, const uint32_t value, const uint8_t size) override;
};
}

View file

@ -0,0 +1,26 @@
// StrikeBox NV2A PNVIO (VGA sequencer and graph controller registers) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
//
// PNVIO engine registers occupy the range 0x0C0000..0x0C0FFF.
#pragma once
#include "engine.h"
namespace strikebox::nv2a {
// NV2A VGA sequencer and graph controller registers (PNVIO)
class PNVIO : public NV2AEngine {
public:
PNVIO(const NV2A& nv2a) : NV2AEngine("PNVIO", 0x0C0000, 0x1000, nv2a) {}
uint32_t Read(const uint32_t addr, const uint8_t size) override;
void Write(const uint32_t addr, const uint32_t value, const uint8_t size) override;
};
}

View file

@ -0,0 +1,26 @@
// StrikeBox NV2A PRAMDAC (RAMDAC, video overlay, cursor, and PLL control) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
//
// PRAMDAC engine registers occupy the range 0x680000..0x680FFF.
#pragma once
#include "engine.h"
namespace strikebox::nv2a {
// NV2A RAMDAC, video overlay, cursor, and PLL control engine (PRAMDAC)
class PRAMDAC : public NV2AEngine {
public:
PRAMDAC(const NV2A& nv2a) : NV2AEngine("PRAMDAC", 0x680000, 0x1000, nv2a) {}
uint32_t Read(const uint32_t addr, const uint8_t size) override;
void Write(const uint32_t addr, const uint32_t value, const uint8_t size) override;
};
}

View file

@ -0,0 +1,28 @@
// StrikeBox NV2A PRAMIN (RAMIN access) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
//
// PRAMIN contains a memory area reserved by the kernel used to describe GPU objects.
//
// PRAMIN engine registers occupy the range 0x700000..0x7FFFFF.
#pragma once
#include "engine.h"
namespace strikebox::nv2a {
// NV2A RAMIN access engine (PRAMIN)
class PRAMIN : public NV2AEngine {
public:
PRAMIN(const NV2A& nv2a) : NV2AEngine("PRAMIN", 0x700000, 0x100000, nv2a) {}
uint32_t Read(const uint32_t addr, const uint8_t size) override;
void Write(const uint32_t addr, const uint32_t value, const uint8_t size) override;
};
}

View file

@ -0,0 +1,28 @@
// StrikeBox NV2A PRMA (Real mode BAR access) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
//
// PRMA provides access to BAR registers through real mode.
//
// PRMA engine registers occupy the range 0x007000..0x007FFF.
#pragma once
#include "engine.h"
namespace strikebox::nv2a {
// NV2A real mode BAR access (PRMA)
class PRMA : public NV2AEngine {
public:
PRMA(const NV2A& nv2a) : NV2AEngine("PRMA", 0x007000, 0x1000, nv2a) {}
uint32_t Read(const uint32_t addr, const uint8_t size) override;
void Write(const uint32_t addr, const uint32_t value, const uint8_t size) override;
};
}

View file

@ -0,0 +1,26 @@
// StrikeBox NV2A PRMCIO (VGA CRTC and attribute controller registers) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
//
// PRMCIO engine registers occupy the range 0x601000..0x601FFF.
#pragma once
#include "engine.h"
namespace strikebox::nv2a {
// NV2A VGA CRTC and attribute controller registers engine (PRMCIO)
class PRMCIO : public NV2AEngine {
public:
PRMCIO(const NV2A& nv2a) : NV2AEngine("PRMCIO", 0x601000, 0x1000, nv2a) {}
uint32_t Read(const uint32_t addr, const uint8_t size) override;
void Write(const uint32_t addr, const uint32_t value, const uint8_t size) override;
};
}

View file

@ -0,0 +1,26 @@
// StrikeBox NV2A PRMDIO (VGA DAC registers) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
//
// PRMDIO engine registers occupy the range 0x681000..0x681FFF.
#pragma once
#include "engine.h"
namespace strikebox::nv2a {
// NV2A VGA DAC registers engine (PRMDIO)
class PRMDIO : public NV2AEngine {
public:
PRMDIO(const NV2A& nv2a) : NV2AEngine("PRMDIO", 0x681000, 0x1000, nv2a) {}
uint32_t Read(const uint32_t addr, const uint8_t size) override;
void Write(const uint32_t addr, const uint32_t value, const uint8_t size) override;
};
}

View file

@ -0,0 +1,26 @@
// StrikeBox NV2A PROM (ROM access window) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
//
// PROM engine registers occupy the range 0x300000..0x31FFFF.
#pragma once
#include "engine.h"
namespace strikebox::nv2a {
// NV2A ROM access window engine (PROM)
class PROM : public NV2AEngine {
public:
PROM(const NV2A& nv2a) : NV2AEngine("PROM", 0x300000, 0x20000, nv2a) {}
uint32_t Read(const uint32_t addr, const uint8_t size) override;
void Write(const uint32_t addr, const uint32_t value, const uint8_t size) override;
};
}

View file

@ -0,0 +1,36 @@
// StrikeBox NV2A PSTRAPS (Straps readout) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
//
// [https://envytools.readthedocs.io/en/latest/hw/io/pstraps.html]
// "The nvidia GPU chips are used in multiple cards from multiple manufacturers.
// Thus, the a single GPU can end up in many different configurations, with varying memory amount, memory type, bus type,
// TV norm, crystal frequency, and many other parameters. Since the GPU often needs to know what configuration it is used in,
// a "straps" mechanism was invented to tell it this information.
// On the first few cycles after reset, the memory bus pins are sampled. Since nothing else is driving them at that point,
// their logic state is decided by the pull-up or pull-down resistors placed by board manufacturer.
// The value this read is used as the "straps" value and is used to configure many aspects of GPU operation.
// Some of the straps are not used by the GPU itself, but are intended for use by the BIOS or the driver."
//
// PSTRAPS engine registers occupy the range 0x101000..0x101FFF.
#pragma once
#include "engine.h"
namespace strikebox::nv2a {
// NV2A straps readout engine (PSTRAPS)
class PSTRAPS : public NV2AEngine {
public:
PSTRAPS(const NV2A& nv2a) : NV2AEngine("PSTRAPS", 0x101000, 0x1000, nv2a) {}
uint32_t Read(const uint32_t addr, const uint8_t size) override;
void Write(const uint32_t addr, const uint32_t value, const uint8_t size) override;
};
}

View file

@ -0,0 +1,33 @@
// StrikeBox NV2A PTIMER (Time measurement and time-based alarms) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
//
// [https://envytools.readthedocs.io/en/latest/hw/bus/ptimer.html]
// "PTIMER is a small functional unit used to measure time by the card.
// It has a 56-bit tick counter connected to a programmable clock source.
// The current value of this counter is used for timestamping by many other units on the GPU.
// Two such timestamps can be substracted to get the wall time elapsed between their creation and measure eg. command execution time.
// Also, it's possible to set up an interrupt that will be triggered when the low 27 bits of the counter reach a specified value."
//
// PTIMER engine registers occupy the range 0x009000..0x009FFF.
#pragma once
#include "engine.h"
namespace strikebox::nv2a {
// NV2A time measurement and time-based alarms (PTIMER)
class PTIMER : public NV2AEngine {
public:
PTIMER(const NV2A& nv2a) : NV2AEngine("PTIMER", 0x009000, 0x1000, nv2a) {}
uint32_t Read(const uint32_t addr, const uint8_t size) override;
void Write(const uint32_t addr, const uint32_t value, const uint8_t size) override;
};
}

View file

@ -0,0 +1,26 @@
// StrikeBox NV2A PVIDEO (Video overlay) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
//
// PVIDEO engine registers occupy the range 0x008000..0x008FFF.
#pragma once
#include "engine.h"
namespace strikebox::nv2a {
// NV2A video overlay engine (PVIDEO)
class PVIDEO : public NV2AEngine {
public:
PVIDEO(const NV2A& nv2a) : NV2AEngine("PVIDEO", 0x008000, 0x1000, nv2a) {}
uint32_t Read(const uint32_t addr, const uint8_t size) override;
void Write(const uint32_t addr, const uint32_t value, const uint8_t size) override;
};
}

View file

@ -0,0 +1,18 @@
// StrikeBox NV2A state class
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
#pragma once
namespace strikebox::nv2a {
// Represents the state of the NV2A GPU.
class NV2A {
};
}

View file

@ -0,0 +1,29 @@
// StrikeBox NV2A USER (PFIFO MMIO/DMA submission area) emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
//
// The USER area is a portion of shared system memory where FIFO commands are submitted
// for processing by the GPU.
//
// USER engine registers occupy the range 0x800000..0x9FFFFF.
#pragma once
#include "engine.h"
namespace strikebox::nv2a {
// NV2A PFIFO MMIO/DMA submission area (USER)
class USER : public NV2AEngine {
public:
USER(const NV2A& nv2a) : NV2AEngine("USER", 0x800000, 0x200000, nv2a) {}
uint32_t Read(const uint32_t addr, const uint8_t size) override;
void Write(const uint32_t addr, const uint32_t value, const uint8_t size) override;
};
}

View file

@ -1,7 +1,12 @@
#pragma once
#include <string>
#include <map>
#include <optional>
#include "pci.h"
#include "../basic/irq.h"
#include "../gpu/nv2a.h"
namespace strikebox {
@ -23,6 +28,32 @@ private:
uint8_t *m_pSystemRAM;
uint32_t m_systemRAMSize;
IRQHandler& m_irqHandler;
// NV2A state and engines
nv2a::NV2A m_nv2a;
nv2a::PMC m_pmc { m_nv2a };
nv2a::PBUS m_pbus { m_nv2a };
nv2a::PFIFO m_pfifo { m_nv2a };
nv2a::PRMA m_prma { m_nv2a };
nv2a::PVIDEO m_pvideo { m_nv2a };
nv2a::PTIMER m_ptimer { m_nv2a };
nv2a::PCOUNTER m_pcounter{ m_nv2a };
nv2a::PNVIO m_pnvio { m_nv2a };
nv2a::PFB m_pfb { m_nv2a };
nv2a::PSTRAPS m_pstraps { m_nv2a };
nv2a::PROM m_prom { m_nv2a };
nv2a::PGRAPH m_pgraph { m_nv2a };
nv2a::PCRTC m_pcrtc { m_nv2a };
nv2a::PRMCIO m_prmcio { m_nv2a };
nv2a::PRAMDAC m_pramdac { m_nv2a };
nv2a::PRMDIO m_prmdio { m_nv2a };
nv2a::PRAMIN m_pramin { m_nv2a };
nv2a::USER m_user { m_nv2a };
// Fast engine lookup
std::map<uint32_t, nv2a::NV2AEngine&> engines;
void RegisterEngine(nv2a::NV2AEngine& engine);
std::optional<std::reference_wrapper<nv2a::NV2AEngine>> FindEngine(const uint32_t address);
};
}

View file

@ -0,0 +1,24 @@
// StrikeBox NV2A PBUS (Bus control) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
#include "strikebox/hw/gpu/pbus.h"
#include "strikebox/log.h"
namespace strikebox::nv2a {
uint32_t PBUS::Read(const uint32_t addr, const uint8_t size) {
log_spew("[NV2A] PBUS::Read: Unimplemented read! address = 0x%x, size = %u\n", addr, size);
return 0;
}
void PBUS::Write(const uint32_t addr, const uint32_t value, const uint8_t size) {
log_spew("[NV2A] PBUS::Write: Unimplemented write! address = 0x%x, value = 0x%x, size = %u\n", addr, value, size);
}
}

View file

@ -0,0 +1,24 @@
// StrikeBox NV2A PCOUNTER (Performance monitoring counters) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
#include "strikebox/hw/gpu/pcounter.h"
#include "strikebox/log.h"
namespace strikebox::nv2a {
uint32_t PCOUNTER::Read(const uint32_t addr, const uint8_t size) {
log_spew("[NV2A] PCOUNTER::Read: Unimplemented read! address = 0x%x, size = %u\n", addr, size);
return 0;
}
void PCOUNTER::Write(const uint32_t addr, const uint32_t value, const uint8_t size) {
log_spew("[NV2A] PCOUNTER::Write: Unimplemented write! address = 0x%x, value = 0x%x, size = %u\n", addr, value, size);
}
}

View file

@ -0,0 +1,24 @@
// StrikeBox NV2A PCRTC (CRTC controls) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
#include "strikebox/hw/gpu/pcrtc.h"
#include "strikebox/log.h"
namespace strikebox::nv2a {
uint32_t PCRTC::Read(const uint32_t addr, const uint8_t size) {
log_spew("[NV2A] PCRTC::Read: Unimplemented read! address = 0x%x, size = %u\n", addr, size);
return 0;
}
void PCRTC::Write(const uint32_t addr, const uint32_t value, const uint8_t size) {
log_spew("[NV2A] PCRTC::Write: Unimplemented write! address = 0x%x, value = 0x%x, size = %u\n", addr, value, size);
}
}

View file

@ -0,0 +1,24 @@
// StrikeBox NV2A PFB (Memory interface) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
#include "strikebox/hw/gpu/pfb.h"
#include "strikebox/log.h"
namespace strikebox::nv2a {
uint32_t PFB::Read(const uint32_t addr, const uint8_t size) {
log_spew("[NV2A] PFB::Read: Unimplemented read! address = 0x%x, size = %u\n", addr, size);
return 0;
}
void PFB::Write(const uint32_t addr, const uint32_t value, const uint8_t size) {
log_spew("[NV2A] PFB::Write: Unimplemented write! address = 0x%x, value = 0x%x, size = %u\n", addr, value, size);
}
}

View file

@ -0,0 +1,24 @@
// StrikeBox NV2A PFIFO (MMIO and DMA FIFO submission to PGRAPH) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
#include "strikebox/hw/gpu/pfifo.h"
#include "strikebox/log.h"
namespace strikebox::nv2a {
uint32_t PFIFO::Read(const uint32_t addr, const uint8_t size) {
log_spew("[NV2A] PFIFO::Read: Unimplemented read! address = 0x%x, size = %u\n", addr, size);
return 0;
}
void PFIFO::Write(const uint32_t addr, const uint32_t value, const uint8_t size) {
log_spew("[NV2A] PFIFO::Write: Unimplemented write! address = 0x%x, value = 0x%x, size = %u\n", addr, value, size);
}
}

View file

@ -0,0 +1,24 @@
// StrikeBox NV2A PGRAPH (2D/3D graphics engine) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
#include "strikebox/hw/gpu/pgraph.h"
#include "strikebox/log.h"
namespace strikebox::nv2a {
uint32_t PGRAPH::Read(const uint32_t addr, const uint8_t size) {
log_spew("[NV2A] PGRAPH::Read: Unimplemented read! address = 0x%x, size = %u\n", addr, size);
return 0;
}
void PGRAPH::Write(const uint32_t addr, const uint32_t value, const uint8_t size) {
log_spew("[NV2A] PGRAPH::Write: Unimplemented write! address = 0x%x, value = 0x%x, size = %u\n", addr, value, size);
}
}

View file

@ -0,0 +1,24 @@
// StrikeBox NV2A PMC (Master control) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
#include "strikebox/hw/gpu/pmc.h"
#include "strikebox/log.h"
namespace strikebox::nv2a {
uint32_t PMC::Read(const uint32_t addr, const uint8_t size) {
log_spew("[NV2A] PMC::Read: Unimplemented read! address = 0x%x, size = %u\n", addr, size);
return 0;
}
void PMC::Write(const uint32_t addr, const uint32_t value, const uint8_t size) {
log_spew("[NV2A] PMC::Write: Unimplemented write! address = 0x%x, value = 0x%x, size = %u\n", addr, value, size);
}
}

View file

@ -0,0 +1,24 @@
// StrikeBox NV2A PNVIO (VGA sequencer and graph controller registers) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
#include "strikebox/hw/gpu/pnvio.h"
#include "strikebox/log.h"
namespace strikebox::nv2a {
uint32_t PNVIO::Read(const uint32_t addr, const uint8_t size) {
log_spew("[NV2A] PNVIO::Read: Unimplemented read! address = 0x%x, size = %u\n", addr, size);
return 0;
}
void PNVIO::Write(const uint32_t addr, const uint32_t value, const uint8_t size) {
log_spew("[NV2A] PNVIO::Write: Unimplemented write! address = 0x%x, value = 0x%x, size = %u\n", addr, value, size);
}
}

View file

@ -0,0 +1,24 @@
// StrikeBox NV2A PRAMDAC (RAMDAC, video overlay, cursor, and PLL control) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
#include "strikebox/hw/gpu/pramdac.h"
#include "strikebox/log.h"
namespace strikebox::nv2a {
uint32_t PRAMDAC::Read(const uint32_t addr, const uint8_t size) {
log_spew("[NV2A] PRAMDAC::Read: Unimplemented read! address = 0x%x, size = %u\n", addr, size);
return 0;
}
void PRAMDAC::Write(const uint32_t addr, const uint32_t value, const uint8_t size) {
log_spew("[NV2A] PRAMDAC::Write: Unimplemented write! address = 0x%x, value = 0x%x, size = %u\n", addr, value, size);
}
}

View file

@ -0,0 +1,24 @@
// StrikeBox NV2A PRAMIN (RAMIN access) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
#include "strikebox/hw/gpu/pramin.h"
#include "strikebox/log.h"
namespace strikebox::nv2a {
uint32_t PRAMIN::Read(const uint32_t addr, const uint8_t size) {
log_spew("[NV2A] PRAMIN::Read: Unimplemented read! address = 0x%x, size = %u\n", addr, size);
return 0;
}
void PRAMIN::Write(const uint32_t addr, const uint32_t value, const uint8_t size) {
log_spew("[NV2A] PRAMIN::Write: Unimplemented write! address = 0x%x, value = 0x%x, size = %u\n", addr, value, size);
}
}

View file

@ -0,0 +1,24 @@
// StrikeBox NV2A PRMA (Real mode BAR access) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
#include "strikebox/hw/gpu/prma.h"
#include "strikebox/log.h"
namespace strikebox::nv2a {
uint32_t PRMA::Read(const uint32_t addr, const uint8_t size) {
log_spew("[NV2A] PRMA::Read: Unimplemented read! address = 0x%x, size = %u\n", addr, size);
return 0;
}
void PRMA::Write(const uint32_t addr, const uint32_t value, const uint8_t size) {
log_spew("[NV2A] PRMA::Write: Unimplemented write! address = 0x%x, value = 0x%x, size = %u\n", addr, value, size);
}
}

View file

@ -0,0 +1,24 @@
// StrikeBox NV2A PRMCIO (VGA CRTC and attribute controller registers) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
#include "strikebox/hw/gpu/prmcio.h"
#include "strikebox/log.h"
namespace strikebox::nv2a {
uint32_t PRMCIO::Read(const uint32_t addr, const uint8_t size) {
log_spew("[NV2A] PRMCIO::Read: Unimplemented read! address = 0x%x, size = %u\n", addr, size);
return 0;
}
void PRMCIO::Write(const uint32_t addr, const uint32_t value, const uint8_t size) {
log_spew("[NV2A] PRMCIO::Write: Unimplemented write! address = 0x%x, value = 0x%x, size = %u\n", addr, value, size);
}
}

View file

@ -0,0 +1,24 @@
// StrikeBox NV2A PRMDIO (VGA DAC registers) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
#include "strikebox/hw/gpu/prmdio.h"
#include "strikebox/log.h"
namespace strikebox::nv2a {
uint32_t PRMDIO::Read(const uint32_t addr, const uint8_t size) {
log_spew("[NV2A] PRMDIO::Read: Unimplemented read! address = 0x%x, size = %u\n", addr, size);
return 0;
}
void PRMDIO::Write(const uint32_t addr, const uint32_t value, const uint8_t size) {
log_spew("[NV2A] PRMDIO::Write: Unimplemented write! address = 0x%x, value = 0x%x, size = %u\n", addr, value, size);
}
}

View file

@ -0,0 +1,24 @@
// StrikeBox NV2A PROM (ROM access window) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
#include "strikebox/hw/gpu/prom.h"
#include "strikebox/log.h"
namespace strikebox::nv2a {
uint32_t PROM::Read(const uint32_t addr, const uint8_t size) {
log_spew("[NV2A] PROM::Read: Unimplemented read! address = 0x%x, size = %u\n", addr, size);
return 0;
}
void PROM::Write(const uint32_t addr, const uint32_t value, const uint8_t size) {
log_spew("[NV2A] PROM::Write: Unimplemented write! address = 0x%x, value = 0x%x, size = %u\n", addr, value, size);
}
}

View file

@ -0,0 +1,24 @@
// StrikeBox NV2A PSTRAPS (Straps readout) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
#include "strikebox/hw/gpu/pstraps.h"
#include "strikebox/log.h"
namespace strikebox::nv2a {
uint32_t PSTRAPS::Read(const uint32_t addr, const uint8_t size) {
log_spew("[NV2A] PSTRAPS::Read: Unimplemented read! address = 0x%x, size = %u\n", addr, size);
return 0;
}
void PSTRAPS::Write(const uint32_t addr, const uint32_t value, const uint8_t size) {
log_spew("[NV2A] PSTRAPS::Write: Unimplemented write! address = 0x%x, value = 0x%x, size = %u\n", addr, value, size);
}
}

View file

@ -0,0 +1,24 @@
// StrikeBox NV2A PTIMER (Time measurement and time-based alarms) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
#include "strikebox/hw/gpu/ptimer.h"
#include "strikebox/log.h"
namespace strikebox::nv2a {
uint32_t PTIMER::Read(const uint32_t addr, const uint8_t size) {
log_spew("[NV2A] PTIMER::Read: Unimplemented read! address = 0x%x, size = %u\n", addr, size);
return 0;
}
void PTIMER::Write(const uint32_t addr, const uint32_t value, const uint8_t size) {
log_spew("[NV2A] PTIMER::Write: Unimplemented write! address = 0x%x, value = 0x%x, size = %u\n", addr, value, size);
}
}

View file

@ -0,0 +1,24 @@
// StrikeBox NV2A PVIDEO (Video overlay) engine emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
#include "strikebox/hw/gpu/pvideo.h"
#include "strikebox/log.h"
namespace strikebox::nv2a {
uint32_t PVIDEO::Read(const uint32_t addr, const uint8_t size) {
log_spew("[NV2A] PVIDEO::Read: Unimplemented read! address = 0x%x, size = %u\n", addr, size);
return 0;
}
void PVIDEO::Write(const uint32_t addr, const uint32_t value, const uint8_t size) {
log_spew("[NV2A] PVIDEO::Write: Unimplemented write! address = 0x%x, value = 0x%x, size = %u\n", addr, value, size);
}
}

View file

@ -0,0 +1,24 @@
// StrikeBox NV2A USER (PFIFO MMIO/DMA submission area) emulation
// (C) Ivan "StrikerX3" Oliveira
//
// Based on envytools:
// https://envytools.readthedocs.io/en/latest/index.html
//
// References to particular items in the documentation are denoted between
// brackets optionally followed by a quote from the documentation.
#include "strikebox/hw/gpu/user.h"
#include "strikebox/log.h"
namespace strikebox::nv2a {
uint32_t USER::Read(const uint32_t addr, const uint8_t size) {
log_spew("[NV2A] USER::Read: Unimplemented read! address = 0x%x, size = %u\n", addr, size);
return 0;
}
void USER::Write(const uint32_t addr, const uint32_t value, const uint8_t size) {
log_spew("[NV2A] USER::Write: Unimplemented write! address = 0x%x, value = 0x%x, size = %u\n", addr, value, size);
}
}

View file

@ -4,31 +4,6 @@
namespace strikebox {
// TODO: implement engines
// Refer to envytools: https://envytools.readthedocs.io/en/latest/index.html
//
// Engine Offset Length Description
// ----------------------------------------------------------------------------
// PMC 0x000000 0x1000 Master control
// PBUS 0x001000 0x1000 Bus control
// PFIFO 0x002000 0x2000 MMIO and DMA FIFO submission to PGRAPH (there's no VPE in NV2A)
// PRMA 0x007000 0x1000 Real mode BAR access
// PVIDEO 0x008000 0x1000 Video overlay
// PTIMER 0x009000 0x1000 Time measurement and time-based alarms
// PCOUNTER 0x00A000 0x1000 Performance monitoring counters
// PMVIO 0x0C0000 0x1000 VGA sequencer and graph controller registers
// PFB 0x100000 0x1000 Memory interface
// PSTRAPS 0x101000 0x1000 Straps readout
// PROM 0x300000 0x20000 ROM access window
// PGRAPH 0x400000 0x2000 2D/3D graphics engine
// PCRTC 0x600000 0x1000 CRTC controls
// PRMCIO 0x601000 0x1000 VGA CRTC and attribute controller registers
// PRAMDAC 0x680000 0x1000 RAMDAC, video overlay, cursor, and PLL control
// PRMDIO 0x681000 0x1000 VGA DAC registers
// PRAMIN 0x700000 0x100000 RAMIN access
// USER 0x800000 0x200000 PFIFO MMIO/DMA submission area
//
NV2ADevice::NV2ADevice(uint8_t *pSystemRAM, uint32_t systemRAMSize, IRQHandler& irqHandler)
: PCIDevice(PCI_HEADER_TYPE_NORMAL, PCI_VENDOR_ID_NVIDIA, 0x02A0, 0xA1,
0x03, 0x00, 0x00) // VGA-compatible controller
@ -36,6 +11,24 @@ NV2ADevice::NV2ADevice(uint8_t *pSystemRAM, uint32_t systemRAMSize, IRQHandler&
, m_systemRAMSize(systemRAMSize)
, m_irqHandler(irqHandler)
{
RegisterEngine(m_pmc);
RegisterEngine(m_pbus);
RegisterEngine(m_pfifo);
RegisterEngine(m_prma);
RegisterEngine(m_pvideo);
RegisterEngine(m_ptimer);
RegisterEngine(m_pcounter);
RegisterEngine(m_pnvio);
RegisterEngine(m_pfb);
RegisterEngine(m_pstraps);
RegisterEngine(m_prom);
RegisterEngine(m_pgraph);
RegisterEngine(m_pcrtc);
RegisterEngine(m_prmcio);
RegisterEngine(m_pramdac);
RegisterEngine(m_prmdio);
RegisterEngine(m_pramin);
RegisterEngine(m_user);
}
NV2ADevice::~NV2ADevice() {
@ -80,21 +73,60 @@ void NV2ADevice::Reset() {
}
void NV2ADevice::PCIIORead(int barIndex, uint32_t port, uint32_t *value, uint8_t size) {
log_warning("NV2ADevice::IORead: Unexpected I/O read! bar = %d, port = 0x%x, size = %u\n", barIndex, port, size);
log_warning("NV2ADevice::PCIIORead: Unexpected I/O read! bar = %d, port = 0x%x, size = %u\n", barIndex, port, size);
*value = 0;
}
void NV2ADevice::PCIIOWrite(int barIndex, uint32_t port, uint32_t value, uint8_t size) {
log_warning("NV2ADevice::IOWrite: Unexpected I/O write! bar = %d, port = 0x%x, size = %u, value = 0x%x\n", barIndex, port, size, value);
log_warning("NV2ADevice::PCIIOWrite: Unexpected I/O write! bar = %d, port = 0x%x, size = %u, value = 0x%x\n", barIndex, port, size, value);
}
void NV2ADevice::PCIMMIORead(int barIndex, uint32_t addr, uint32_t *value, uint8_t size) {
*value = 0;
log_spew("NV2ADevice::PCIMMIORead: Unimplemented read! bar = %d, address = 0x%x, size = %u\n", barIndex, addr, size);
if (barIndex == 0) {
auto opt_eng = FindEngine(addr);
if (opt_eng) {
auto& eng = opt_eng->get();
*value = eng.Read(addr - eng.GetOffset(), size);
}
else {
log_spew("NV2ADevice::PCIMMIORead: Unmapped read! bar = %d, address = 0x%x, size = %u\n", barIndex, addr, size);
}
}
else {
log_spew("NV2ADevice::PCIMMIORead: Unimplemented read! bar = %d, address = 0x%x, size = %u\n", barIndex, addr, size);
*value = 0;
}
}
void NV2ADevice::PCIMMIOWrite(int barIndex, uint32_t addr, uint32_t value, uint8_t size) {
log_spew("NV2ADevice::PCIMMIOWrite: Unimplemented write! bar = %d, address = 0x%x, value = 0x%x, size = %u\n", barIndex, addr, value, size);
if (barIndex == 0) {
auto opt_eng = FindEngine(addr);
if (opt_eng) {
auto& eng = opt_eng->get();
eng.Write(addr - eng.GetOffset(), value, size);
}
else {
log_spew("NV2ADevice::PCIMMIOWrite: Unmapped write! bar = %d, address = 0x%x, value = 0x%x, size = %u\n", barIndex, addr, value, size);
}
}
else {
log_spew("NV2ADevice::PCIMMIOWrite: Unimplemented write! bar = %d, address = 0x%x, value = 0x%x, size = %u\n", barIndex, addr, value, size);
}
}
void NV2ADevice::RegisterEngine(nv2a::NV2AEngine& engine) {
engines.insert({ engine.GetOffset() + engine.GetLength() - 1, engine });
}
std::optional<std::reference_wrapper<nv2a::NV2AEngine>> NV2ADevice::FindEngine(const uint32_t address) {
auto entry = engines.lower_bound(address);
if (entry != engines.end()) {
auto& engine = entry->second;
if (engine.Contains(address)) {
return engine;
}
}
return std::nullopt;
}
}