/** ** Supermodel ** A Sega Model 3 Arcade Emulator. ** Copyright 2011 Bart Trzynadlowski, Nik Henson ** ** This file is part of Supermodel. ** ** Supermodel is free software: you can redistribute it and/or modify it under ** the terms of the GNU General Public License as published by the Free ** Software Foundation, either version 3 of the License, or (at your option) ** any later version. ** ** Supermodel is distributed in the hope that it will be useful, but WITHOUT ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ** more details. ** ** You should have received a copy of the GNU General Public License along ** with Supermodel. If not, see . **/ /* * Real3D.h * * Header file defining the CReal3D class: the Model 3's Real3D-based graphics * hardware. */ #ifndef INCLUDED_REAL3D_H #define INCLUDED_REAL3D_H #include "IRQ.h" #include "PCI.h" #include "CPU/Bus.h" #include "Graphics/IRender3D.h" #include "Util/NewConfig.h" #include #include /* * QueuedUploadTextures: * * When rendering is multi-threaded, this struct is used to represent a postponed * call to CRender3D::UploadTextures that will be performed by the render thread * at the beginning of the next frame, rather than directly in the PPC thread. */ struct QueuedUploadTextures { unsigned level; // mipmap level of the texture, saves calculating this later unsigned x; unsigned y; unsigned width; unsigned height; }; /* * CReal3D: * * Model 3 Real3D-based graphics hardware. This class manages the hardware * state and drives the rendering process (scene database traversal). Actual * rasterization and matrix transformations are carried out by the graphics * engine. */ class CReal3D: public IPCIDevice { public: /* * PCI IDs * * The CReal3D object must be configured with the desired ID. Some Step 2.x * appear to defy this and expect the 1.x ID. The symptom of this is that * VBL is enabled briefly then disabled. This should be investigated further. * Perhaps a different ASIC's PCI ID is being read in these situations? * * The vendor ID code 0x11db is Sega's. */ enum PCIID: uint32_t { Step1x = 0x16C311DB, // Step 1.x Step2x = 0x178611DB // Step 2.x }; /* * ASIC Names * * These were determined from Virtual On, which prints them out if any of the * ID codes are incorrect. ID codes depend on stepping. */ enum ASIC { Mercury, Venus, Earth, Mars, Jupiter }; /* * SaveState(SaveState): * * Saves an image of the current device state. * * Parameters: * SaveState Block file to save state information to. */ void SaveState(CBlockFile *SaveState); /* * LoadState(SaveState): * * Loads and a state image. * * Parameters: * SaveState Block file to load state information from. */ void LoadState(CBlockFile *SaveState); /* * BeginVBlank(void): * * Must be called before the VBlank starts. */ void BeginVBlank(int statusCycles); /* * EndVBlank(void) * * Must be called after the VBlank finishes. */ void EndVBlank(void); /* * SyncSnapshots(void): * * Syncs the read-only memory snapshots with the real ones so that rendering * of the current frame can begin in the render thread. Must be called at the * end of each frame when both the render thread and the PPC thread have finished * their work. If multi-threaded rendering is not enabled, then this method does * nothing. */ uint32_t SyncSnapshots(void); /* * BeginFrame(void): * * Prepares to render a new frame. Must be called once per frame prior to * drawing anything and must only access read-only snapshots and variables * since it may be running in a separate thread. */ void BeginFrame(void); /* * RenderFrame(void): * * Traverses the scene database and renders a frame. Must be called after * BeginFrame() but before EndFrame() and must only access read-only snapshots * and variables since it may be running in a separate thread. */ void RenderFrame(void); /* * EndFrame(void): * * Signals the end of rendering for this frame. Must be called last during * the frame and must only access read-only snapshots and variables since it * may be running in a separate thread. */ void EndFrame(void); /* * Flush(void): * * Triggers the beginning of a new frame. All textures in the texture FIFO * are uploaded and the FIFO is reset. On the real device, this seems to * cause a frame to be rendered as well but this is not performed here. * * This should be called when the command port is written. */ void Flush(void); /* * ReadDMARegister8(reg): * ReadDMARegister32(reg): * * Reads from a DMA register. Multi-byte reads are returned as little * endian and must be flipped if called by a big endian device. * * Parameters: * reg Register number to read from (0-0xFF only). * * Returns: * Data of the requested size, in little endian. */ uint8_t ReadDMARegister8(unsigned reg); uint32_t ReadDMARegister32(unsigned reg); /* * WriteDMARegister8(reg, data): * WriteDMARegister32(reg, data); * * Write to a DMA register. Multi-byte writes by big endian devices must be * byte reversed (this is a little endian device). * * Parameters: * reg Register number to read from (0-0xFF only). * data Data to write. */ void WriteDMARegister8(unsigned reg, uint8_t data); void WriteDMARegister32(unsigned reg, uint32_t data); /* * WriteLowCullingRAM(addr, data): * * Writes the low culling RAM region. Because this is a little endian * device, big endian devices/buses have to take care to manually reverse * the data before writing. * * Parameters: * addr Word (32-bit) aligned address ranging from 0 to 0x3FFFFC. * User must ensure address is properly clamped. * data Data to write. */ void WriteLowCullingRAM(uint32_t addr, uint32_t data); /* * WriteHighCullingRAM(addr, data): * * Writes the high culling RAM region. Because this is a little endian * device, big endian devices/buses have to take care to manually reverse * the data before writing. * * Parameters: * addr Word (32-bit) aligned address ranging from 0 to 0xFFFFC. * User must ensure address is properly clamped. * data Data to write. */ void WriteHighCullingRAM(uint32_t addr, uint32_t data); /* * WriteTextureFIFO(data): * * Writes to the 1MB texture FIFO. Because this is a little endian device, * big endian devices/buses have to take care to manually reverse the data * before writing. * * Parameters: * data Data to write. */ void WriteTextureFIFO(uint32_t data); /* * WriteTexturePort(reg, data): * * Writes to the VROM texture ports. Register 0 is the word-granular VROM * address of the texture, register 4 is the texture information header, * and register 8 is the size of the texture in words. * * Parameters: * reg Register number: must be 0, 4, 8, 0xC, 0x10, or 0x14 only. * data The 32-bit word to write to the register. A write to * register 8 triggers the upload. */ void WriteTexturePort(unsigned reg, uint32_t data); /* * WritePolygonRAM(addr, data): * * Writes the polygon RAM region. Because this is a little endian device, * big endian devices/buses have to take care to manually reverse the data * before writing. * * Parameters: * addr Word (32-bit) aligned address ranging from 0 to 0x3FFFFC. * User must ensure address is properly clamped. * data Data to write. */ void WritePolygonRAM(uint32_t addr, uint32_t data); /* * WriteJTAGRegister(instruction, data): * * Write to an internal register using the JTAG interface. This is intended * to be called from the JTAG emulation for instructions that are known to * poke the internal state of Real3D ASICs. * * Parameters: * instruction Value of the JTAG instruction register. * data Data written. */ void WriteJTAGRegister(uint64_t instruction, uint64_t data); /* * ReadRegister(reg): * * Reads one of the status registers. * * Parameters: * reg Register offset (32-bit aligned). From 0x00 to 0x3C. * * Returns: * The 32-bit status register. */ uint32_t ReadRegister(unsigned reg); /* * ReadPCIConfigSpace(device, reg, bits, offset): * * Reads a PCI configuration space register. See CPCIDevice definition for * more details. * * Parameters: * device Device number (ignored, not needed). * reg Register number. * bits Bit width of access (8, 16, or 32 only).; * offset Byte offset within register, aligned to the specified bit * width, and offset from the 32-bit aligned base of the * register number. * * Returns: * Register data. */ uint32_t ReadPCIConfigSpace(unsigned device, unsigned reg, unsigned bits, unsigned width); /* * WritePCIConfigSpace(device, reg, bits, offset, data): * * Writes to a PCI configuration space register. See CPCIDevice definition * for more details. * * Parameters: * device Device number (ignored, not needed). * reg Register number. * bits Bit width of access (8, 16, or 32 only). * offset Byte offset within register, aligned to the specified bit * width, and offset from the 32-bit aligned base of the * register number. * data Data. */ void WritePCIConfigSpace(unsigned device, unsigned reg, unsigned bits, unsigned width, uint32_t data); /* * Reset(void): * * Resets the Real3D device. Must be called before reading/writing the * device. */ void Reset(void); /* * AttachRenderer(render3DPtr): * * Attaches a 3D renderer for the Real3D to use. This function will * immediately pass along the information that a CRender3D object needs to * work with. * * Parameters: * Render3DPtr Pointer to a 3D renderer object. */ void AttachRenderer(IRender3D *Render3DPtr); /* * GetASICIDCodes(asic): * * Obtain ASIC ID code for the specified ASIC under the currently configured * hardware stepping. * * Parameters: * asic ASIC ID. * * Returns: * The ASIC ID code. Undefined for invalid ASIC ID. */ uint32_t GetASICIDCode(ASIC asic) const; /* * SetStepping(stepping, pciIDValue): * * Sets the Model 3 hardware stepping, which also determines the Real3D * functionality. The default is Step 1.0. This should be called prior to * any other emulation functions and after Init(). * * Parameters: * stepping 0x10 for Step 1.0, 0x15 for Step 1.5, 0x20 for Step 2.0, or * 0x21 for Step 2.1. Anything else defaults to 1.0. * pciIDValue The PCI ID code to return. This should be one of the PCIID * enum values otherwise games may fail to boot. Although the * PCI ID depends on stepping, there are a few games that * have to be explicitly configured with an older ID code, * which is why this parameter is exposed. */ void SetStepping(int stepping, uint32_t pciIDValue); /* * Init(vromPtr, BusObjectPtr, IRQObjectPtr, dmaIRQBit): * * One-time initialization of the context. Must be called prior to all * other members. Connects the Real3D device to its video ROM and allocates * memory for RAM regions. * * Parameters: * vromPtr A pointer to video ROM (with each 32-bit word in * its native little endian format). * BusObjectPtr Pointer to the bus that the 53C810 has control * over. Used to read/write memory. * IRQObjectPtr Pointer to the IRQ controller. Used to trigger SCSI * and DMA interrupts. * dmaIRQBit IRQ identifier bit to pass along to IRQ controller * when asserting interrupts. * * Returns: * OKAY if successful otherwise FAIL (not enough memory). Prints own * errors. */ bool Init(const uint8_t *vromPtr, IBus *BusObjectPtr, CIRQ *IRQObjectPtr, unsigned dmaIRQBit); /* * CReal3D(config): * ~CReal3D(void): * * Constructor and destructor. * * Paramters: * config Run-time configuration. The reference should be held because * this changes at run-time. */ CReal3D(const Util::Config::Node &config); ~CReal3D(void); private: // Private member functions void DMACopy(void); void StoreTexture(unsigned level, unsigned xPos, unsigned yPos, unsigned width, unsigned height, const uint16_t *texData, bool sixteenBit, bool writeLSB, bool writeMSB, uint32_t &texDataOffset); void UploadTexture(uint32_t header, const uint16_t *texData); uint32_t UpdateSnapshots(bool copyWhole); uint32_t UpdateSnapshot(bool copyWhole, uint8_t *src, uint8_t *dst, unsigned size, uint8_t *dirty); // Config const Util::Config::Node &m_config; const bool m_gpuMultiThreaded; // Renderer attached to the Real3D IRender3D *Render3D; // Data passed from Model 3 object const uint32_t *vrom; // Video ROM int step; // hardware stepping (as in GameInfo structure) uint32_t pciID; // PCI vendor and device ID // Error flag (to limit errors to once per frame) bool error; // true if an error occurred this frame // Real3D memory uint8_t *memoryPool; // all memory allocated here uint32_t *cullingRAMLo; // 4MB of culling RAM at 8C000000 uint32_t *cullingRAMHi; // 1MB of culling RAM at 8E000000 uint32_t *polyRAM; // 4MB of polygon RAM at 98000000 uint16_t *textureRAM; // 8MB of internal texture RAM uint32_t *textureFIFO; // 1MB texture FIFO at 0x94000000 uint32_t fifoIdx; // index into texture FIFO uint32_t m_vromTextureFIFO[2]; uint32_t m_vromTextureFIFOIdx; // Read-only snapshots uint32_t *cullingRAMLoRO; // 4MB of culling RAM at 8C000000 [read-only snapshot] uint32_t *cullingRAMHiRO; // 1MB of culling RAM at 8E000000 [read-only snapshot] uint32_t *polyRAMRO; // 4MB of polygon RAM at 98000000 [read-only snapshot] uint16_t *textureRAMRO; // 8MB of internal texture RAM [read-only snapshot] // Arrays to keep track of dirty pages in memory regions uint8_t *cullingRAMLoDirty; uint8_t *cullingRAMHiDirty; uint8_t *polyRAMDirty; uint8_t *textureRAMDirty; // Queued texture uploads std::vector queuedUploadTextures; std::vector queuedUploadTexturesRO; // Read-only copy of queue // Big endian bus object for DMA memory access IBus *Bus; // IRQ handling CIRQ *IRQ; // IRQ controller uint32_t dmaIRQ; // IRQ bit to use when calling IRQ handler // DMA device uint32_t dmaSrc; uint32_t dmaDest; uint32_t dmaLength; uint32_t dmaData; uint32_t dmaUnknownReg; uint8_t dmaStatus; uint8_t dmaConfig; // Command port bool commandPortWritten; bool commandPortWrittenRO; // Read-only copy of flag // Status and command registers uint32_t m_pingPong; uint64_t statusChange = 0; bool m_evenFrame = false; // Internal ASIC state std::map m_asicID; uint64_t m_internalRenderConfig[2]; }; #endif // INCLUDED_REAL3D_H