Supermodel/Src/Model3/Real3D.h

472 lines
15 KiB
C++

/**
** 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 <http://www.gnu.org/licenses/>.
**/
/*
* 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 <cstdint>
/*
* 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:
/*
* 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);
/*
* ReadTAP(void):
*
* Reads the JTAG Test Access Port.
*
* Returns:
* The TDO bit (either 1 or 0).
*/
unsigned ReadTAP(void);
/*
* void WriteTAP(tck, tms, tdi, trst):
*
* Writes to the JTAG TAP. State changes only occur on the rising edge of
* the clock (tck = 1). Each of the inputs is a single bit only and must be
* either 0 or 1, or the code will fail.
*
* Parameters:
* tck Clock.
* tms Test mode select.
* tdi Serial data input. Must be 0 or 1 only!
* trst Reset.
*/
void WriteTAP(unsigned tck, unsigned tms, unsigned tdi, unsigned trst);
/*
* 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);
/*
* SetStepping(stepping):
*
* 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.
*/
void SetStepping(int stepping);
/*
* 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 InsertBit(uint8_t *buf, unsigned bitNum, unsigned bit);
void InsertID(uint32_t id, unsigned startBit);
unsigned Shift(uint8_t *data, unsigned numBits);
void StoreTexture(unsigned level, unsigned xPos, unsigned yPos, unsigned width, unsigned height, const uint16_t *texData, uint32_t header);
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
vector<QueuedUploadTextures> queuedUploadTextures;
vector<QueuedUploadTextures> 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
uint64_t statusChange;
// JTAG Test Access Port
uint64_t tapCurrentInstruction; // latched IR (not always equal to IR)
uint64_t tapIR; // instruction register (46 bits)
uint8_t tapID[32]; // ASIC ID code data buffer
unsigned tapIDSize; // size of ID data in bits
unsigned tapTDO; // bit shifted out to TDO
unsigned tapState; // current state
};
#endif // INCLUDED_REAL3D_H