mirror of
https://github.com/StrikerX3/StrikeBox.git
synced 2024-06-23 14:53:22 -04:00
Implement a few registers and move engines to NV2A state class
This commit is contained in:
parent
cf0deb7d47
commit
5e623da2e9
|
@ -11,14 +11,14 @@
|
|||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "state.h"
|
||||
|
||||
namespace strikebox::nv2a {
|
||||
|
||||
class 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)
|
||||
NV2AEngine(const std::string name, const uint32_t offset, const uint32_t length, NV2A& nv2a)
|
||||
: m_name(name)
|
||||
, m_offset(offset)
|
||||
, m_length(length)
|
||||
|
@ -27,8 +27,11 @@ public:
|
|||
{}
|
||||
|
||||
virtual void Reset() = 0;
|
||||
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;
|
||||
virtual uint32_t Read(const uint32_t addr) = 0;
|
||||
virtual void Write(const uint32_t addr, const uint32_t value) = 0;
|
||||
|
||||
virtual uint32_t ReadUnaligned(const uint32_t addr, const uint8_t size);
|
||||
virtual void WriteUnaligned(const uint32_t addr, const uint32_t value, const uint8_t size);
|
||||
|
||||
const std::string GetName() const noexcept { return m_name; }
|
||||
const uint32_t GetOffset() const noexcept { return m_offset; }
|
||||
|
@ -36,12 +39,14 @@ public:
|
|||
|
||||
const bool Contains(uint32_t address) const noexcept { return address >= m_offset && address < m_offsetEnd; }
|
||||
|
||||
protected:
|
||||
NV2A& m_nv2a;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -36,22 +36,3 @@
|
|||
|
||||
#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"
|
||||
|
|
|
@ -22,11 +22,13 @@ namespace strikebox::nv2a {
|
|||
// NV2A bus control engine (PBUS)
|
||||
class PBUS : public NV2AEngine {
|
||||
public:
|
||||
PBUS(const NV2A& nv2a) : NV2AEngine("PBUS", 0x001000, 0x1000, nv2a) {}
|
||||
PBUS(NV2A& nv2a) : NV2AEngine("PBUS", 0x001000, 0x1000, nv2a) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset() override;
|
||||
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;
|
||||
uint32_t Read(const uint32_t addr) override;
|
||||
void Write(const uint32_t addr, const uint32_t value) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -24,11 +24,13 @@ namespace strikebox::nv2a {
|
|||
// NV2A performance monitoring counters engine (PCOUNTER)
|
||||
class PCOUNTER : public NV2AEngine {
|
||||
public:
|
||||
PCOUNTER(const NV2A& nv2a) : NV2AEngine("PCOUNTER", 0x00A000, 0x1000, nv2a) {}
|
||||
PCOUNTER(NV2A& nv2a) : NV2AEngine("PCOUNTER", 0x00A000, 0x1000, nv2a) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset() override;
|
||||
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;
|
||||
uint32_t Read(const uint32_t addr) override;
|
||||
void Write(const uint32_t addr, const uint32_t value) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -17,11 +17,13 @@ namespace strikebox::nv2a {
|
|||
// NV2A CRTC controls engine (PCRTC)
|
||||
class PCRTC : public NV2AEngine {
|
||||
public:
|
||||
PCRTC(const NV2A& nv2a) : NV2AEngine("PCRTC", 0x600000, 0x1000, nv2a) {}
|
||||
PCRTC(NV2A& nv2a) : NV2AEngine("PCRTC", 0x600000, 0x1000, nv2a) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset() override;
|
||||
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;
|
||||
uint32_t Read(const uint32_t addr) override;
|
||||
void Write(const uint32_t addr, const uint32_t value) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -17,11 +17,13 @@ namespace strikebox::nv2a {
|
|||
// NV2A memory interface engine (PFB)
|
||||
class PFB : public NV2AEngine {
|
||||
public:
|
||||
PFB(const NV2A& nv2a) : NV2AEngine("PFB", 0x100000, 0x1000, nv2a) {}
|
||||
PFB(NV2A& nv2a) : NV2AEngine("PFB", 0x100000, 0x1000, nv2a) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset() override;
|
||||
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;
|
||||
uint32_t Read(const uint32_t addr) override;
|
||||
void Write(const uint32_t addr, const uint32_t value) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -23,11 +23,13 @@ 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) {}
|
||||
PFIFO(NV2A& nv2a) : NV2AEngine("PFIFO", 0x002000, 0x2000, nv2a) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset() override;
|
||||
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;
|
||||
uint32_t Read(const uint32_t addr) override;
|
||||
void Write(const uint32_t addr, const uint32_t value) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -19,11 +19,13 @@ namespace strikebox::nv2a {
|
|||
// NV2A 2D/3D graphics engine (PGRAPH)
|
||||
class PGRAPH : public NV2AEngine {
|
||||
public:
|
||||
PGRAPH(const NV2A& nv2a) : NV2AEngine("PGRAPH", 0x400000, 0x2000, nv2a) {}
|
||||
PGRAPH(NV2A& nv2a) : NV2AEngine("PGRAPH", 0x400000, 0x2000, nv2a) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset() override;
|
||||
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;
|
||||
uint32_t Read(const uint32_t addr) override;
|
||||
void Write(const uint32_t addr, const uint32_t value) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -21,11 +21,13 @@ namespace strikebox::nv2a {
|
|||
// NV2A master control engine (PMC)
|
||||
class PMC : public NV2AEngine {
|
||||
public:
|
||||
PMC(const NV2A& nv2a) : NV2AEngine("PMC", 0x000000, 0x1000, nv2a) {}
|
||||
PMC(NV2A& nv2a) : NV2AEngine("PMC", 0x000000, 0x1000, nv2a) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset() override;
|
||||
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;
|
||||
uint32_t Read(const uint32_t addr) override;
|
||||
void Write(const uint32_t addr, const uint32_t value) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -17,11 +17,13 @@ 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) {}
|
||||
PNVIO(NV2A& nv2a) : NV2AEngine("PNVIO", 0x0C0000, 0x1000, nv2a) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset() override;
|
||||
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;
|
||||
uint32_t Read(const uint32_t addr) override;
|
||||
void Write(const uint32_t addr, const uint32_t value) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -17,11 +17,20 @@ 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) {}
|
||||
PRAMDAC(NV2A& nv2a) : NV2AEngine("PRAMDAC", 0x680000, 0x1000, nv2a) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset() override;
|
||||
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;
|
||||
uint32_t Read(const uint32_t addr) override;
|
||||
void Write(const uint32_t addr, const uint32_t value) override;
|
||||
|
||||
private:
|
||||
uint32_t m_coreClockCoeff;
|
||||
uint32_t m_memoryClockCoeff;
|
||||
uint32_t m_videoClockCoeff;
|
||||
|
||||
uint32_t m_mem[0x1000 / 4]; // for all other reads/writes
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -19,11 +19,13 @@ namespace strikebox::nv2a {
|
|||
// NV2A RAMIN access engine (PRAMIN)
|
||||
class PRAMIN : public NV2AEngine {
|
||||
public:
|
||||
PRAMIN(const NV2A& nv2a) : NV2AEngine("PRAMIN", 0x700000, 0x100000, nv2a) {}
|
||||
PRAMIN(NV2A& nv2a) : NV2AEngine("PRAMIN", 0x700000, 0x100000, nv2a) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset() override;
|
||||
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;
|
||||
uint32_t Read(const uint32_t addr) override;
|
||||
void Write(const uint32_t addr, const uint32_t value) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -19,11 +19,13 @@ namespace strikebox::nv2a {
|
|||
// NV2A real mode BAR access (PRMA)
|
||||
class PRMA : public NV2AEngine {
|
||||
public:
|
||||
PRMA(const NV2A& nv2a) : NV2AEngine("PRMA", 0x007000, 0x1000, nv2a) {}
|
||||
PRMA(NV2A& nv2a) : NV2AEngine("PRMA", 0x007000, 0x1000, nv2a) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset() override;
|
||||
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;
|
||||
uint32_t Read(const uint32_t addr) override;
|
||||
void Write(const uint32_t addr, const uint32_t value) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -17,11 +17,13 @@ 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) {}
|
||||
PRMCIO(NV2A& nv2a) : NV2AEngine("PRMCIO", 0x601000, 0x1000, nv2a) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset() override;
|
||||
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;
|
||||
uint32_t Read(const uint32_t addr) override;
|
||||
void Write(const uint32_t addr, const uint32_t value) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -17,11 +17,13 @@ namespace strikebox::nv2a {
|
|||
// NV2A VGA DAC registers engine (PRMDIO)
|
||||
class PRMDIO : public NV2AEngine {
|
||||
public:
|
||||
PRMDIO(const NV2A& nv2a) : NV2AEngine("PRMDIO", 0x681000, 0x1000, nv2a) {}
|
||||
PRMDIO(NV2A& nv2a) : NV2AEngine("PRMDIO", 0x681000, 0x1000, nv2a) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset() override;
|
||||
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;
|
||||
uint32_t Read(const uint32_t addr) override;
|
||||
void Write(const uint32_t addr, const uint32_t value) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -17,11 +17,13 @@ namespace strikebox::nv2a {
|
|||
// NV2A ROM access window engine (PROM)
|
||||
class PROM : public NV2AEngine {
|
||||
public:
|
||||
PROM(const NV2A& nv2a) : NV2AEngine("PROM", 0x300000, 0x20000, nv2a) {}
|
||||
PROM(NV2A& nv2a) : NV2AEngine("PROM", 0x300000, 0x20000, nv2a) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset() override;
|
||||
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;
|
||||
uint32_t Read(const uint32_t addr) override;
|
||||
void Write(const uint32_t addr, const uint32_t value) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -27,11 +27,13 @@ namespace strikebox::nv2a {
|
|||
// NV2A straps readout engine (PSTRAPS)
|
||||
class PSTRAPS : public NV2AEngine {
|
||||
public:
|
||||
PSTRAPS(const NV2A& nv2a) : NV2AEngine("PSTRAPS", 0x101000, 0x1000, nv2a) {}
|
||||
PSTRAPS(NV2A& nv2a) : NV2AEngine("PSTRAPS", 0x101000, 0x1000, nv2a) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset() override;
|
||||
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;
|
||||
uint32_t Read(const uint32_t addr) override;
|
||||
void Write(const uint32_t addr, const uint32_t value) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -24,11 +24,13 @@ 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) {}
|
||||
PTIMER(NV2A& nv2a) : NV2AEngine("PTIMER", 0x009000, 0x1000, nv2a) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset() override;
|
||||
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;
|
||||
uint32_t Read(const uint32_t addr) override;
|
||||
void Write(const uint32_t addr, const uint32_t value) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -17,11 +17,13 @@ namespace strikebox::nv2a {
|
|||
// NV2A video overlay engine (PVIDEO)
|
||||
class PVIDEO : public NV2AEngine {
|
||||
public:
|
||||
PVIDEO(const NV2A& nv2a) : NV2AEngine("PVIDEO", 0x008000, 0x1000, nv2a) {}
|
||||
PVIDEO(NV2A& nv2a) : NV2AEngine("PVIDEO", 0x008000, 0x1000, nv2a) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset() override;
|
||||
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;
|
||||
uint32_t Read(const uint32_t addr) override;
|
||||
void Write(const uint32_t addr, const uint32_t value) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -8,11 +8,77 @@
|
|||
// brackets optionally followed by a quote from the documentation.
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <functional>
|
||||
|
||||
#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"
|
||||
|
||||
namespace strikebox::nv2a {
|
||||
|
||||
using PCIConfigReader = std::function<uint32_t(uint8_t address)>;
|
||||
using PCIConfigWriter = std::function<void(uint8_t address, uint32_t value)>;
|
||||
|
||||
// Represents the state of the NV2A GPU.
|
||||
class NV2A {
|
||||
public:
|
||||
NV2A(uint8_t* systemRAM, uint32_t systemRAMSize, PCIConfigReader pciCfgReader, PCIConfigWriter pciCfgWriter);
|
||||
|
||||
std::unique_ptr<PMC> pmc = std::make_unique<PMC>(*this);
|
||||
std::unique_ptr<PBUS> pbus = std::make_unique<PBUS>(*this);
|
||||
std::unique_ptr<PFIFO> pfifo = std::make_unique<PFIFO>(*this);
|
||||
std::unique_ptr<PRMA> prma = std::make_unique<PRMA>(*this);
|
||||
std::unique_ptr<PVIDEO> pvideo = std::make_unique<PVIDEO>(*this);
|
||||
std::unique_ptr<PTIMER> ptimer = std::make_unique<PTIMER>(*this);
|
||||
std::unique_ptr<PCOUNTER> pcounter = std::make_unique<PCOUNTER>(*this);
|
||||
std::unique_ptr<PNVIO> pnvio = std::make_unique<PNVIO>(*this);
|
||||
std::unique_ptr<PFB> pfb = std::make_unique<PFB>(*this);
|
||||
std::unique_ptr<PSTRAPS> pstraps = std::make_unique<PSTRAPS>(*this);
|
||||
std::unique_ptr<PROM> prom = std::make_unique<PROM>(*this);
|
||||
std::unique_ptr<PGRAPH> pgraph = std::make_unique<PGRAPH>(*this);
|
||||
std::unique_ptr<PCRTC> pcrtc = std::make_unique<PCRTC>(*this);
|
||||
std::unique_ptr<PRMCIO> prmcio = std::make_unique<PRMCIO>(*this);
|
||||
std::unique_ptr<PRAMDAC> pramdac = std::make_unique<PRAMDAC>(*this);
|
||||
std::unique_ptr<PRMDIO> prmdio = std::make_unique<PRMDIO>(*this);
|
||||
std::unique_ptr<PRAMIN> pramin = std::make_unique<PRAMIN>(*this);
|
||||
std::unique_ptr<USER> user = std::make_unique<USER>(*this);
|
||||
|
||||
uint8_t* systemRAM;
|
||||
const uint32_t systemRAMSize;
|
||||
|
||||
void Reset();
|
||||
uint32_t Read(const uint32_t addr, const uint8_t size);
|
||||
void Write(const uint32_t addr, const uint32_t value, const uint8_t size);
|
||||
|
||||
// PCI config space read/write access
|
||||
const PCIConfigReader pciCfgReader;
|
||||
const PCIConfigWriter pciCfgWriter;
|
||||
|
||||
private:
|
||||
// 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);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -20,11 +20,13 @@ namespace strikebox::nv2a {
|
|||
// NV2A PFIFO MMIO/DMA submission area (USER)
|
||||
class USER : public NV2AEngine {
|
||||
public:
|
||||
USER(const NV2A& nv2a) : NV2AEngine("USER", 0x800000, 0x200000, nv2a) {}
|
||||
USER(NV2A& nv2a) : NV2AEngine("USER", 0x800000, 0x200000, nv2a) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset() override;
|
||||
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;
|
||||
uint32_t Read(const uint32_t addr) override;
|
||||
void Write(const uint32_t addr, const uint32_t value) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <memory>
|
||||
|
||||
#include "pci.h"
|
||||
#include "../basic/irq.h"
|
||||
|
@ -25,35 +23,10 @@ public:
|
|||
void PCIMMIOWrite(int barIndex, uint32_t addr, uint32_t value, uint8_t size) override;
|
||||
|
||||
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);
|
||||
// NV2A state
|
||||
std::unique_ptr<nv2a::NV2A> m_nv2a;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
45
modules/core/src/common/strikebox/hw/gpu/engine.cpp
Normal file
45
modules/core/src/common/strikebox/hw/gpu/engine.cpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
// 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/state.h"
|
||||
|
||||
#include "strikebox/log.h"
|
||||
|
||||
namespace strikebox::nv2a {
|
||||
|
||||
uint32_t NV2AEngine::ReadUnaligned(const uint32_t addr, const uint8_t size) {
|
||||
// Unaligned read fits in one register
|
||||
if ((addr & ~3) == ((addr + size - 1) & ~3)) {
|
||||
log_warning("NV2AEngine::Read: Unaligned read! address = 0x%x, size = %u\n", addr, size);
|
||||
uint8_t offset = (addr & 3) * 8;
|
||||
uint32_t mask = 0xFFFFFFFF >> (32 - size * 8);
|
||||
return (Read(addr & ~3) >> offset) & mask;
|
||||
}
|
||||
|
||||
// Unaligned read spans two registers, corresponding to one of these cases:
|
||||
// - 16-bit read from offset 3
|
||||
// - 32-bit read from offsets 1, 2 or 3
|
||||
// FIXME: how does the real hardware behave in this case?
|
||||
log_warning("NV2AEngine::Read: Severely unaligned read! address = 0x%x, size = %u\n", addr, size);
|
||||
|
||||
uint32_t value1 = Read(addr & ~3);
|
||||
uint32_t value2 = Read((addr & ~3) + 4);
|
||||
|
||||
uint8_t offset = (addr & 3) * 8;
|
||||
uint32_t mask = 0xFFFFFFFF >> (32 - size * 8);
|
||||
return ((value1 >> offset) | (value2 << (32 - offset))) & mask;
|
||||
}
|
||||
|
||||
void NV2AEngine::WriteUnaligned(const uint32_t addr, const uint32_t value, const uint8_t size) {
|
||||
log_warning("NV2AEngine::Write: Unaligned write! address = 0x%x, size = %u\n", addr, size);
|
||||
// FIXME: how does the real hardware behave in this case?
|
||||
// This is almost certainly wrong.
|
||||
Write(addr & ~3, value);
|
||||
}
|
||||
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
// 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/hw/gpu/state.h"
|
||||
|
||||
#include "strikebox/log.h"
|
||||
|
||||
|
@ -15,13 +16,24 @@ namespace strikebox::nv2a {
|
|||
void PBUS::Reset() {
|
||||
}
|
||||
|
||||
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);
|
||||
uint32_t PBUS::Read(const uint32_t addr) {
|
||||
if (addr >= 0x800 && addr <= 0x8FF) {
|
||||
// PCI Configuration Space access
|
||||
return m_nv2a.pciCfgReader(addr - 0x800);
|
||||
}
|
||||
|
||||
log_spew("[NV2A] PBUS::Read: Unimplemented read! address = 0x%x\n", addr);
|
||||
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);
|
||||
void PBUS::Write(const uint32_t addr, const uint32_t value) {
|
||||
if (addr >= 0x800 && addr <= 0x8FF) {
|
||||
// PCI Configuration Space access
|
||||
m_nv2a.pciCfgWriter(addr - 0x800, value);
|
||||
}
|
||||
else {
|
||||
log_spew("[NV2A] PBUS::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,13 +15,13 @@ namespace strikebox::nv2a {
|
|||
void PCOUNTER::Reset() {
|
||||
}
|
||||
|
||||
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);
|
||||
uint32_t PCOUNTER::Read(const uint32_t addr) {
|
||||
log_spew("[NV2A] PCOUNTER::Read: Unimplemented read! address = 0x%x\n", addr);
|
||||
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);
|
||||
void PCOUNTER::Write(const uint32_t addr, const uint32_t value) {
|
||||
log_spew("[NV2A] PCOUNTER::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,13 +15,13 @@ namespace strikebox::nv2a {
|
|||
void PCRTC::Reset() {
|
||||
}
|
||||
|
||||
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);
|
||||
uint32_t PCRTC::Read(const uint32_t addr) {
|
||||
log_spew("[NV2A] PCRTC::Read: Unimplemented read! address = 0x%x\n", addr);
|
||||
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);
|
||||
void PCRTC::Write(const uint32_t addr, const uint32_t value) {
|
||||
log_spew("[NV2A] PCRTC::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,21 +7,32 @@
|
|||
// 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/hw/gpu/state.h"
|
||||
|
||||
#include "strikebox/log.h"
|
||||
|
||||
namespace strikebox::nv2a {
|
||||
|
||||
static const uint32_t Reg_CFG0 = 0x200;
|
||||
static const uint32_t Reg_CSTATUS = 0x20C; // Framebuffer size
|
||||
static const uint32_t Reg_WBC = 0x410; // Write-back cache?
|
||||
|
||||
void PFB::Reset() {
|
||||
}
|
||||
|
||||
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;
|
||||
uint32_t PFB::Read(const uint32_t addr) {
|
||||
switch (addr) {
|
||||
case Reg_CFG0: return 3; // The kernel asserts this value to be 3 early during initialization
|
||||
case Reg_CSTATUS: return m_nv2a.systemRAMSize;
|
||||
case Reg_WBC: return 0;
|
||||
default:
|
||||
log_spew("[NV2A] PFB::Read: Unimplemented read! address = 0x%x\n", addr);
|
||||
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);
|
||||
void PFB::Write(const uint32_t addr, const uint32_t value) {
|
||||
log_spew("[NV2A] PFB::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,13 +15,13 @@ namespace strikebox::nv2a {
|
|||
void PFIFO::Reset() {
|
||||
}
|
||||
|
||||
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);
|
||||
uint32_t PFIFO::Read(const uint32_t addr) {
|
||||
log_spew("[NV2A] PFIFO::Read: Unimplemented read! address = 0x%x\n", addr);
|
||||
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);
|
||||
void PFIFO::Write(const uint32_t addr, const uint32_t value) {
|
||||
log_spew("[NV2A] PFIFO::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,13 +15,13 @@ namespace strikebox::nv2a {
|
|||
void PGRAPH::Reset() {
|
||||
}
|
||||
|
||||
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);
|
||||
uint32_t PGRAPH::Read(const uint32_t addr) {
|
||||
log_spew("[NV2A] PGRAPH::Read: Unimplemented read! address = 0x%x\n", addr);
|
||||
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);
|
||||
void PGRAPH::Write(const uint32_t addr, const uint32_t value) {
|
||||
log_spew("[NV2A] PGRAPH::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,13 +15,13 @@ namespace strikebox::nv2a {
|
|||
void PMC::Reset() {
|
||||
}
|
||||
|
||||
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);
|
||||
uint32_t PMC::Read(const uint32_t addr) {
|
||||
log_spew("[NV2A] PMC::Read: Unimplemented read! address = 0x%x\n", addr);
|
||||
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);
|
||||
void PMC::Write(const uint32_t addr, const uint32_t value) {
|
||||
log_spew("[NV2A] PMC::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,13 +15,13 @@ namespace strikebox::nv2a {
|
|||
void PNVIO::Reset() {
|
||||
}
|
||||
|
||||
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);
|
||||
uint32_t PNVIO::Read(const uint32_t addr) {
|
||||
log_spew("[NV2A] PNVIO::Read: Unimplemented read! address = 0x%x\n", addr);
|
||||
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);
|
||||
void PNVIO::Write(const uint32_t addr, const uint32_t value) {
|
||||
log_spew("[NV2A] PNVIO::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,16 +12,57 @@
|
|||
|
||||
namespace strikebox::nv2a {
|
||||
|
||||
static const uint32_t Reg_NVPLL = 0x500; // Core PLL clock
|
||||
static const uint32_t Reg_MPLL = 0x504; // Memory PLL clock
|
||||
static const uint32_t Reg_VPLL = 0x508; // Video PLL clocks
|
||||
|
||||
// [https://envytools.readthedocs.io/en/latest/hw/display/nv3/pramdac.html]
|
||||
// "The bit layout for all NV4 PLLs is that bits 18-16 are P, bits 15-8 are N, and bits 7-0 are M."
|
||||
union ClockCoefficients {
|
||||
struct {
|
||||
uint8_t M;
|
||||
uint8_t N;
|
||||
uint8_t P : 3;
|
||||
};
|
||||
uint32_t u32;
|
||||
};
|
||||
|
||||
void PRAMDAC::Reset() {
|
||||
// NV2A clocks:
|
||||
// crystal = 16.6 MHz
|
||||
// core = 233 MHz
|
||||
// memory = 200 MHz
|
||||
// video = 25.160 MHz
|
||||
//
|
||||
// The clocks are calculated as such: (Crystal frequency * N) / (1 << P) / M.
|
||||
m_coreClockCoeff = ClockCoefficients{ 1, 28, 1 }.u32;
|
||||
m_memoryClockCoeff = ClockCoefficients{ 1, 24, 1 }.u32;
|
||||
m_videoClockCoeff = ClockCoefficients{ 3, 157, 13 }.u32;
|
||||
|
||||
std::fill(std::begin(m_mem), std::end(m_mem), 0);
|
||||
}
|
||||
|
||||
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;
|
||||
uint32_t PRAMDAC::Read(const uint32_t addr) {
|
||||
switch (addr) {
|
||||
case Reg_NVPLL: return m_coreClockCoeff;
|
||||
case Reg_MPLL: return m_memoryClockCoeff;
|
||||
case Reg_VPLL: return m_videoClockCoeff;
|
||||
default:
|
||||
//log_spew("[NV2A] PRAMDAC::Read: Unimplemented read! address = 0x%x\n", addr);
|
||||
return m_mem[addr >> 2];
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
void PRAMDAC::Write(const uint32_t addr, const uint32_t value) {
|
||||
switch (addr) {
|
||||
case Reg_NVPLL: m_coreClockCoeff = value; break;
|
||||
case Reg_MPLL: m_memoryClockCoeff = value; break;
|
||||
case Reg_VPLL: m_videoClockCoeff = value; break;
|
||||
default:
|
||||
//log_spew("[NV2A] PRAMDAC::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value);
|
||||
m_mem[addr >> 2] = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,13 +15,13 @@ namespace strikebox::nv2a {
|
|||
void PRAMIN::Reset() {
|
||||
}
|
||||
|
||||
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);
|
||||
uint32_t PRAMIN::Read(const uint32_t addr) {
|
||||
log_spew("[NV2A] PRAMIN::Read: Unimplemented read! address = 0x%x\n", addr);
|
||||
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);
|
||||
void PRAMIN::Write(const uint32_t addr, const uint32_t value) {
|
||||
log_spew("[NV2A] PRAMIN::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,13 +15,13 @@ namespace strikebox::nv2a {
|
|||
void PRMA::Reset() {
|
||||
}
|
||||
|
||||
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);
|
||||
uint32_t PRMA::Read(const uint32_t addr) {
|
||||
log_spew("[NV2A] PRMA::Read: Unimplemented read! address = 0x%x\n", addr);
|
||||
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);
|
||||
void PRMA::Write(const uint32_t addr, const uint32_t value) {
|
||||
log_spew("[NV2A] PRMA::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,13 +15,13 @@ namespace strikebox::nv2a {
|
|||
void PRMCIO::Reset() {
|
||||
}
|
||||
|
||||
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);
|
||||
uint32_t PRMCIO::Read(const uint32_t addr) {
|
||||
log_spew("[NV2A] PRMCIO::Read: Unimplemented read! address = 0x%x\n", addr);
|
||||
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);
|
||||
void PRMCIO::Write(const uint32_t addr, const uint32_t value) {
|
||||
log_spew("[NV2A] PRMCIO::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,13 +15,13 @@ namespace strikebox::nv2a {
|
|||
void PRMDIO::Reset() {
|
||||
}
|
||||
|
||||
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);
|
||||
uint32_t PRMDIO::Read(const uint32_t addr) {
|
||||
log_spew("[NV2A] PRMDIO::Read: Unimplemented read! address = 0x%x\n", addr);
|
||||
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);
|
||||
void PRMDIO::Write(const uint32_t addr, const uint32_t value) {
|
||||
log_spew("[NV2A] PRMDIO::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,13 +15,13 @@ namespace strikebox::nv2a {
|
|||
void PROM::Reset() {
|
||||
}
|
||||
|
||||
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);
|
||||
uint32_t PROM::Read(const uint32_t addr) {
|
||||
log_spew("[NV2A] PROM::Read: Unimplemented read! address = 0x%x\n", addr);
|
||||
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);
|
||||
void PROM::Write(const uint32_t addr, const uint32_t value) {
|
||||
log_spew("[NV2A] PROM::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,13 +15,13 @@ namespace strikebox::nv2a {
|
|||
void PSTRAPS::Reset() {
|
||||
}
|
||||
|
||||
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);
|
||||
uint32_t PSTRAPS::Read(const uint32_t addr) {
|
||||
log_spew("[NV2A] PSTRAPS::Read: Unimplemented read! address = 0x%x\n", addr);
|
||||
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);
|
||||
void PSTRAPS::Write(const uint32_t addr, const uint32_t value) {
|
||||
log_spew("[NV2A] PSTRAPS::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,13 +15,13 @@ namespace strikebox::nv2a {
|
|||
void PTIMER::Reset() {
|
||||
}
|
||||
|
||||
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);
|
||||
uint32_t PTIMER::Read(const uint32_t addr) {
|
||||
log_spew("[NV2A] PTIMER::Read: Unimplemented read! address = 0x%x\n", addr);
|
||||
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);
|
||||
void PTIMER::Write(const uint32_t addr, const uint32_t value) {
|
||||
log_spew("[NV2A] PTIMER::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,13 +15,13 @@ namespace strikebox::nv2a {
|
|||
void PVIDEO::Reset() {
|
||||
}
|
||||
|
||||
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);
|
||||
uint32_t PVIDEO::Read(const uint32_t addr) {
|
||||
log_spew("[NV2A] PVIDEO::Read: Unimplemented read! address = 0x%x\n", addr);
|
||||
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);
|
||||
void PVIDEO::Write(const uint32_t addr, const uint32_t value) {
|
||||
log_spew("[NV2A] PVIDEO::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
90
modules/core/src/common/strikebox/hw/gpu/state.cpp
Normal file
90
modules/core/src/common/strikebox/hw/gpu/state.cpp
Normal file
|
@ -0,0 +1,90 @@
|
|||
#include "strikebox/hw/gpu/state.h"
|
||||
|
||||
#include "strikebox/log.h"
|
||||
|
||||
namespace strikebox::nv2a {
|
||||
|
||||
NV2A::NV2A(uint8_t* systemRAM, uint32_t systemRAMSize, PCIConfigReader pciCfgReader, PCIConfigWriter pciCfgWriter)
|
||||
: systemRAM(systemRAM)
|
||||
, systemRAMSize(systemRAMSize)
|
||||
, pciCfgReader(pciCfgReader)
|
||||
, pciCfgWriter(pciCfgWriter)
|
||||
{
|
||||
RegisterEngine(*pmc);
|
||||
RegisterEngine(*pbus);
|
||||
RegisterEngine(*pfifo);
|
||||
RegisterEngine(*prma);
|
||||
RegisterEngine(*pvideo);
|
||||
RegisterEngine(*ptimer);
|
||||
RegisterEngine(*pcounter);
|
||||
RegisterEngine(*pnvio);
|
||||
RegisterEngine(*pfb);
|
||||
RegisterEngine(*pstraps);
|
||||
RegisterEngine(*prom);
|
||||
RegisterEngine(*pgraph);
|
||||
RegisterEngine(*pcrtc);
|
||||
RegisterEngine(*prmcio);
|
||||
RegisterEngine(*pramdac);
|
||||
RegisterEngine(*prmdio);
|
||||
RegisterEngine(*pramin);
|
||||
RegisterEngine(*user);
|
||||
}
|
||||
|
||||
void NV2A::Reset() {
|
||||
for (auto& eng : engines) {
|
||||
eng.second.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t NV2A::Read(const uint32_t addr, const uint8_t size) {
|
||||
auto opt_eng = FindEngine(addr);
|
||||
if (opt_eng) {
|
||||
auto& eng = opt_eng->get();
|
||||
// Aligned 32-bit read as expected
|
||||
if ((addr & 3) == 0 && size == 4) {
|
||||
return eng.Read(addr - eng.GetOffset());
|
||||
}
|
||||
|
||||
// Unaligned or non 32-bit read
|
||||
log_warning("NV2A::Read: Unaligned read! address = 0x%x, size = %u\n", addr, size);
|
||||
return eng.ReadUnaligned(addr - eng.GetOffset(), size);
|
||||
}
|
||||
|
||||
log_spew("NV2A::Read: Unmapped read! address = 0x%x, size = %u\n", addr, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NV2A::Write(const uint32_t addr, const uint32_t value, const uint8_t size) {
|
||||
auto opt_eng = FindEngine(addr);
|
||||
if (opt_eng) {
|
||||
auto& eng = opt_eng->get();
|
||||
// Aligned 32-bit wrute as expected
|
||||
if ((addr & 3) == 0 && size == 4) {
|
||||
eng.Write(addr - eng.GetOffset(), value);
|
||||
}
|
||||
else {
|
||||
// Unaligned or non 32-bit write
|
||||
eng.WriteUnaligned(addr - eng.GetOffset(), value, size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
log_spew("NV2A::Write: Unmapped write! address = 0x%x, value = 0x%x, size = %u\n", addr, value, size);
|
||||
}
|
||||
}
|
||||
|
||||
void NV2A::RegisterEngine(nv2a::NV2AEngine& engine) {
|
||||
engines.insert({ engine.GetOffset() + engine.GetLength() - 1, engine });
|
||||
}
|
||||
|
||||
std::optional<std::reference_wrapper<nv2a::NV2AEngine>> NV2A::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;
|
||||
}
|
||||
|
||||
}
|
|
@ -15,13 +15,13 @@ namespace strikebox::nv2a {
|
|||
void USER::Reset() {
|
||||
}
|
||||
|
||||
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);
|
||||
uint32_t USER::Read(const uint32_t addr) {
|
||||
log_spew("[NV2A] USER::Read: Unimplemented read! address = 0x%x\n", addr);
|
||||
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);
|
||||
void USER::Write(const uint32_t addr, const uint32_t value) {
|
||||
log_spew("[NV2A] USER::Write: Unimplemented write! address = 0x%x, value = 0x%x\n", addr, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,28 +7,11 @@ namespace strikebox {
|
|||
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
|
||||
, m_pSystemRAM(pSystemRAM)
|
||||
, 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);
|
||||
nv2a::PCIConfigReader pciCfgReader = [&](uint8_t addr) -> uint32_t { return Read32(m_configSpace, addr); };
|
||||
nv2a::PCIConfigWriter pciCfgWriter = [&](uint8_t addr, uint32_t value) { Write32(m_configSpace, addr, value); };
|
||||
m_nv2a = std::make_unique<nv2a::NV2A>(pSystemRAM, systemRAMSize, pciCfgReader, pciCfgWriter);
|
||||
}
|
||||
|
||||
NV2ADevice::~NV2ADevice() {
|
||||
|
@ -83,14 +66,7 @@ void NV2ADevice::PCIIOWrite(int barIndex, uint32_t port, uint32_t value, uint8_t
|
|||
|
||||
void NV2ADevice::PCIMMIORead(int barIndex, uint32_t addr, uint32_t *value, uint8_t 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);
|
||||
}
|
||||
*value = m_nv2a->Read(addr, size);
|
||||
}
|
||||
else {
|
||||
log_spew("NV2ADevice::PCIMMIORead: Unimplemented read! bar = %d, address = 0x%x, size = %u\n", barIndex, addr, size);
|
||||
|
@ -100,33 +76,11 @@ void NV2ADevice::PCIMMIORead(int barIndex, uint32_t addr, uint32_t *value, uint8
|
|||
|
||||
void NV2ADevice::PCIMMIOWrite(int barIndex, uint32_t addr, uint32_t value, uint8_t 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);
|
||||
}
|
||||
m_nv2a->Write(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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue