531 lines
12 KiB
C++
531 lines
12 KiB
C++
#ifndef __PCE_VDC_H
|
|
#define __PCE_VDC_H
|
|
|
|
#define VDC_PIXEL_OUT_MASK 0x01FF
|
|
|
|
// This bit will be set for a non-sprite pixel if the BG layer is disabled(via ToggleLayer()),
|
|
#define VDC_BGDISABLE_OUT_MASK 0x0200
|
|
|
|
// HSync and VSync out bits are only valid when the EX bits in VDC's CR
|
|
// are set so that the VDC will output sync signals rather than
|
|
// input them. If it is not configured in this manner, the bit(s) shall always be 0.
|
|
#define VDC_HSYNC_OUT_MASK 0x2000
|
|
#define VDC_VSYNC_OUT_MASK 0x4000
|
|
|
|
// The DISP bit can either denote active display area(1 = active, 0 = inactive),
|
|
// colorburst insertion period(0 = insert colorburst, 1 = not in colorburst period; may not be emulated correctly),
|
|
// or "internal horizontal synchronous signal"(may not be emulated correctly), depending on the TE
|
|
// bits in the VDC's CR.
|
|
#define VDC_DISP_OUT_MASK 0x8000
|
|
|
|
#define VDC_REGSETP(_reg, _data, _msb) \
|
|
{ \
|
|
_reg &= 0xFF << ((_msb) ? 0 : 8); \
|
|
_reg |= (_data) << ((_msb) ? 8 : 0); \
|
|
}
|
|
#define VDC_REGGETP(_reg, _msb) ((_reg >> ((_msb) ? 8 : 0)) & 0xFF)
|
|
|
|
static const unsigned int vram_inc_tab[4] = {1, 32, 64, 128};
|
|
|
|
#define VDC_IS_BSY (pending_read || pending_write)
|
|
|
|
typedef struct
|
|
{
|
|
uint32 x;
|
|
uint32 flags;
|
|
uint8 palette_index;
|
|
uint16 pattern_data[4];
|
|
} SPRLE;
|
|
|
|
typedef struct
|
|
{
|
|
// In the case the VDC access doesn't cause a VRAM read/write, only ReadCount/WriteCount will be set to 0.
|
|
uint32 ReadStart;
|
|
uint32 ReadCount;
|
|
uint32 WriteStart;
|
|
uint32 WriteCount;
|
|
|
|
uint32 RegRWIndex;
|
|
bool RegWriteDone;
|
|
bool RegReadDone;
|
|
} VDC_SimulateResult;
|
|
|
|
class VDC
|
|
{
|
|
public:
|
|
VDC()
|
|
MDFN_COLD;
|
|
~VDC() MDFN_COLD;
|
|
|
|
// Default false.
|
|
void SetUnlimitedSprites(const bool nospritelimit);
|
|
|
|
// The VRAM size is specified in 16-bit words. Default 65536.
|
|
// Reset() should be called after changing this setting, otherwise things may be broken.
|
|
void SetVRAMSize(const uint32 par_VRAM_size);
|
|
|
|
int32 Reset(void) MDFN_WARN_UNUSED_RESULT;
|
|
|
|
// ResetSimulate(), SimulateWrite(), and SimulateRead() are intended to handle VRAM read/write breakpoints.
|
|
// SimulateWrite() and SimulateRead() will return the VRAM address that will EVENTUALLY be written(upper 32-bits) and/or read(lower 32-bits) to
|
|
// due to the access, or 0xFFFFFFFF in the upper or lower 32-bits if no VRAM access of that type occurs.
|
|
//
|
|
// The feature is intended to support block moves to VRAM in a single instruction. It may not function properly if the address passed to SimulateRead()
|
|
// or SimulateWrite() alternates(even if just once) between the data port high byte and control port between calls to ResetSimulate()
|
|
// Call to reset simulation state.
|
|
|
|
INLINE void ResetSimulate(void)
|
|
{
|
|
Simulate_MAWR = MAWR;
|
|
Simulate_MARR = MARR;
|
|
|
|
Simulate_select = select;
|
|
Simulate_CR = CR;
|
|
|
|
Simulate_LENR = LENR;
|
|
}
|
|
|
|
INLINE void SimulateRead(uint32 A, VDC_SimulateResult *result)
|
|
{
|
|
result->ReadCount = 0;
|
|
result->WriteCount = 0;
|
|
result->RegReadDone = false;
|
|
result->RegWriteDone = false;
|
|
|
|
if (A & 0x2)
|
|
{
|
|
result->RegReadDone = true;
|
|
result->RegRWIndex = Simulate_select;
|
|
}
|
|
|
|
if ((A & 0x3) == 0x3 && Simulate_select == 0x02)
|
|
{
|
|
Simulate_MARR += vram_inc_tab[(Simulate_CR >> 11) & 0x3];
|
|
|
|
result->ReadStart = Simulate_MARR;
|
|
result->ReadCount = 1;
|
|
}
|
|
}
|
|
|
|
INLINE void SimulateWrite(uint32 A, uint8 V, VDC_SimulateResult *result)
|
|
{
|
|
result->ReadCount = 0;
|
|
result->WriteCount = 0;
|
|
result->RegReadDone = false;
|
|
result->RegWriteDone = false;
|
|
|
|
const unsigned int msb = A & 1;
|
|
|
|
switch (A & 0x3)
|
|
{
|
|
case 0x00:
|
|
Simulate_select = V & 0x1F;
|
|
break;
|
|
|
|
case 0x02:
|
|
case 0x03:
|
|
result->RegWriteDone = true;
|
|
result->RegRWIndex = Simulate_select;
|
|
|
|
switch (Simulate_select)
|
|
{
|
|
case 0x00:
|
|
VDC_REGSETP(Simulate_MAWR, V, msb);
|
|
break;
|
|
|
|
case 0x01:
|
|
VDC_REGSETP(Simulate_MARR, V, msb);
|
|
Simulate_MARR += vram_inc_tab[(Simulate_CR >> 11) & 0x3];
|
|
|
|
result->ReadStart = Simulate_MARR;
|
|
result->ReadCount = 1;
|
|
break;
|
|
|
|
case 0x02:
|
|
if (msb)
|
|
{
|
|
result->WriteStart = Simulate_MAWR;
|
|
result->WriteCount = 1;
|
|
|
|
Simulate_MAWR += vram_inc_tab[(Simulate_CR >> 11) & 0x3];
|
|
}
|
|
break;
|
|
|
|
case 0x12:
|
|
VDC_REGSETP(Simulate_LENR, V, msb);
|
|
if (msb)
|
|
{
|
|
result->ReadStart = SOUR;
|
|
result->ReadCount = Simulate_LENR + 1;
|
|
|
|
if (DCR & 0x4)
|
|
result->ReadStart = (result->ReadStart - (result->ReadCount - 1)) & 0xFFFF;
|
|
|
|
result->WriteStart = DESR;
|
|
result->WriteCount = Simulate_LENR + 1;
|
|
|
|
if (DCR & 0x8)
|
|
result->WriteStart = (result->WriteStart - (result->WriteCount - 1)) & 0xFFFF;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
INLINE void SimulateRead16(bool A, VDC_SimulateResult *result)
|
|
{
|
|
result->ReadCount = 0;
|
|
result->WriteCount = 0;
|
|
result->RegReadDone = false;
|
|
result->RegWriteDone = false;
|
|
|
|
if (A & 0x2)
|
|
{
|
|
result->RegReadDone = true;
|
|
result->RegRWIndex = Simulate_select;
|
|
}
|
|
|
|
if (A && Simulate_select == 0x02)
|
|
{
|
|
Simulate_MARR += vram_inc_tab[(Simulate_CR >> 11) & 0x3];
|
|
|
|
result->ReadStart = Simulate_MARR;
|
|
result->ReadCount = 1;
|
|
}
|
|
}
|
|
|
|
INLINE void SimulateWrite16(bool A, uint16 V, VDC_SimulateResult *result)
|
|
{
|
|
result->ReadCount = 0;
|
|
result->WriteCount = 0;
|
|
result->RegReadDone = false;
|
|
result->RegWriteDone = false;
|
|
|
|
if (!A)
|
|
Simulate_select = V & 0x1F;
|
|
else
|
|
{
|
|
result->RegWriteDone = true;
|
|
result->RegRWIndex = Simulate_select;
|
|
|
|
switch (Simulate_select)
|
|
{
|
|
case 0x00:
|
|
Simulate_MAWR = V;
|
|
break;
|
|
|
|
case 0x01:
|
|
Simulate_MARR = V;
|
|
Simulate_MARR += vram_inc_tab[(Simulate_CR >> 11) & 0x3];
|
|
|
|
result->ReadStart = Simulate_MARR;
|
|
result->ReadCount = 1;
|
|
break;
|
|
|
|
case 0x02:
|
|
result->WriteStart = Simulate_MAWR;
|
|
result->WriteCount = 1;
|
|
|
|
Simulate_MAWR += vram_inc_tab[(Simulate_CR >> 11) & 0x3];
|
|
break;
|
|
|
|
case 0x12:
|
|
Simulate_LENR = V;
|
|
result->ReadStart = SOUR;
|
|
result->ReadCount = Simulate_LENR + 1;
|
|
|
|
if (DCR & 0x4)
|
|
result->ReadStart = (result->ReadStart - (result->ReadCount - 1)) & 0xFFFF;
|
|
|
|
result->WriteStart = DESR;
|
|
result->WriteCount = Simulate_LENR + 1;
|
|
|
|
if (DCR & 0x8)
|
|
result->WriteStart = (result->WriteStart - (result->WriteCount - 1)) & 0xFFFF;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int32 HSync(bool);
|
|
int32 VSync(bool);
|
|
|
|
void Write(uint32 A, uint8 V, int32 &next_event);
|
|
uint8 Read(uint32 A, int32 &next_event, bool peek = FALSE);
|
|
|
|
void Write16(bool A, uint16 V);
|
|
uint16 Read16(bool A, bool peek = FALSE);
|
|
|
|
int32 Run(int32 clocks, /*bool hs, bool vs,*/ uint16 *pixels, bool skip);
|
|
|
|
void FixTileCache(uint16);
|
|
void SetLayerEnableMask(uint64 mask);
|
|
|
|
void RunDMA(int32, bool force_completion = FALSE);
|
|
void RunSATDMA(int32, bool force_completion = FALSE);
|
|
|
|
void IncRCR(void);
|
|
void DoVBIRQTest(void);
|
|
void HDS_Start(void);
|
|
|
|
// Peek(VRAM/SAT) and Poke(VRAM/SAT) work in 16-bit VRAM word units.
|
|
INLINE uint16 PeekVRAM(uint16 Address)
|
|
{
|
|
if (Address < VRAM_Size)
|
|
return (VRAM[Address]);
|
|
else
|
|
return (0);
|
|
}
|
|
|
|
INLINE uint16 PeekSAT(uint8 Address)
|
|
{
|
|
return (SAT[Address]);
|
|
}
|
|
|
|
INLINE void PokeVRAM(uint16 Address, const uint16 Data)
|
|
{
|
|
if (Address < VRAM_Size)
|
|
{
|
|
VRAM[Address] = Data;
|
|
FixTileCache(Address);
|
|
}
|
|
}
|
|
|
|
INLINE void PokeSAT(uint8 Address, const uint16 Data)
|
|
{
|
|
SAT[Address] = Data;
|
|
}
|
|
|
|
// Register enums for GetRegister() and SetRegister()
|
|
enum
|
|
{
|
|
GSREG_MAWR = 0,
|
|
GSREG_MARR,
|
|
GSREG_CR,
|
|
GSREG_RCR,
|
|
GSREG_BXR,
|
|
GSREG_BYR,
|
|
GSREG_MWR,
|
|
GSREG_HSR,
|
|
GSREG_HDR,
|
|
GSREG_VSR,
|
|
GSREG_VDR,
|
|
GSREG_VCR,
|
|
GSREG_DCR,
|
|
GSREG_SOUR,
|
|
GSREG_DESR,
|
|
GSREG_LENR,
|
|
GSREG_DVSSR,
|
|
|
|
GSREG_SELECT,
|
|
GSREG_STATUS,
|
|
|
|
__GSREG_COUNT
|
|
};
|
|
|
|
// Pass NULL if you don't want more information about the special meaning of the value in the specified
|
|
// register. Otherwise, pass a buffer of at least 256 bytes in size.
|
|
uint32 GetRegister(const unsigned int id, char *special, const uint32 special_len);
|
|
void SetRegister(const unsigned int id, const uint32 value);
|
|
|
|
#ifdef WANT_DEBUGGER
|
|
bool DoGfxDecode(uint32 *target, const uint32 *color_table, const uint32 TransparentColor, bool DecodeSprites,
|
|
int32 w, int32 h, int32 scroll);
|
|
#endif
|
|
|
|
INLINE bool PeekIRQ(void)
|
|
{
|
|
return ((bool)(status & 0x3F));
|
|
}
|
|
|
|
INLINE void SetIRQHook(void (*irqh)(bool))
|
|
{
|
|
IRQHook = irqh;
|
|
}
|
|
|
|
INLINE void SetWSHook(bool (*wsh)(int32))
|
|
{
|
|
WSHook = wsh;
|
|
}
|
|
|
|
INLINE uint16_t* GetVramPointer()
|
|
{
|
|
return VRAM;
|
|
}
|
|
INLINE int GetVramByteSize()
|
|
{
|
|
return VRAM_Size * 2;
|
|
}
|
|
|
|
private:
|
|
int TimeFromHDSStartToBYRLatch(void);
|
|
int TimeFromBYRLatchToBXRLatch(void);
|
|
|
|
enum
|
|
{
|
|
HPHASE_HDS = 0,
|
|
HPHASE_HDS_PART2,
|
|
HPHASE_HDS_PART3,
|
|
HPHASE_HDW,
|
|
HPHASE_HDW_FINAL,
|
|
HPHASE_HDE,
|
|
HPHASE_HSW,
|
|
HPHASE_COUNT
|
|
};
|
|
|
|
enum
|
|
{
|
|
VPHASE_VDS = 0,
|
|
VPHASE_VDW,
|
|
VPHASE_VCR,
|
|
VPHASE_VSW,
|
|
VPHASE_COUNT
|
|
};
|
|
|
|
int VRAM_Size; // = 0x8000;
|
|
int VRAM_SizeMask; // = VRAM_Size - 1; //0x7FFF;
|
|
int VRAM_BGTileNoMask; // = VRAM_SizeMask / 16; //0x7FF;
|
|
|
|
void (*IRQHook)(bool);
|
|
bool (*WSHook)(int32);
|
|
|
|
void DoWaitStates(void);
|
|
void CheckAndCommitPending(void);
|
|
|
|
INLINE int32 CalcNextEvent(void)
|
|
{
|
|
int32 next_event = HPhaseCounter;
|
|
|
|
if (sat_dma_counter > 0 && sat_dma_counter < next_event)
|
|
next_event = sat_dma_counter;
|
|
|
|
if (sprite_cg_fetch_counter > 0 && sprite_cg_fetch_counter < next_event)
|
|
next_event = sprite_cg_fetch_counter;
|
|
|
|
if (DMARunning)
|
|
{
|
|
assert(VDMA_CycleCounter < 2);
|
|
|
|
int32 next_vram_dma_event = ((LENR + 1) * 4) - (DMAReadWrite * 2) - VDMA_CycleCounter;
|
|
|
|
assert(next_vram_dma_event > 0);
|
|
|
|
if (next_vram_dma_event > 0 && next_vram_dma_event < next_event)
|
|
next_event = next_vram_dma_event;
|
|
|
|
//printf("Next VRAM DMA event: %d(LENR = %d)\n", next_vram_dma_event, LENR);
|
|
}
|
|
|
|
assert(next_event > 0);
|
|
return (next_event);
|
|
}
|
|
|
|
bool in_exhsync, in_exvsync;
|
|
|
|
void CalcWidthStartEnd(uint32 &display_width, uint32 &start, uint32 &end);
|
|
void DrawBG(uint16 *target, int enabled);
|
|
void DrawSprites(uint16 *target, int enabled);
|
|
void FetchSpriteData(void);
|
|
|
|
uint8 Simulate_select;
|
|
uint16 Simulate_MAWR;
|
|
uint16 Simulate_MARR;
|
|
uint16 Simulate_CR;
|
|
uint16 Simulate_LENR;
|
|
|
|
int32 sat_dma_counter;
|
|
|
|
uint8 select;
|
|
uint16 MAWR; // Memory Address Write Register
|
|
uint16 MARR; // Memory Address Read Register
|
|
|
|
uint16 CR; // Control Register
|
|
uint16 CR_cache; // Cache for BG/SPR enable
|
|
uint16 RCR; // Raster Compare Register
|
|
uint16 BXR; // Background X-Scroll Register
|
|
uint16 BYR; // Background Y-Scroll Register
|
|
uint16 MWR; // Memory Width Register
|
|
|
|
uint16 HSR; // Horizontal Sync Register
|
|
uint16 HDR; // Horizontal Display Register
|
|
uint16 VSR;
|
|
uint16 VDR;
|
|
|
|
uint16 VCR;
|
|
uint16 DCR;
|
|
uint16 SOUR;
|
|
uint16 DESR;
|
|
uint16 LENR;
|
|
uint16 DVSSR;
|
|
|
|
// Internal SAT DMA transfer variables.
|
|
//uint16 SAT_SOUR;
|
|
//uint16 SAT_DESR;
|
|
//uint16 SAT_LENR;
|
|
|
|
int32 VDMA_CycleCounter;
|
|
|
|
uint32 RCRCount;
|
|
|
|
bool pending_read;
|
|
uint16 pending_read_addr;
|
|
uint16 read_buffer;
|
|
|
|
uint8 write_latch; // LSB
|
|
|
|
bool pending_write;
|
|
uint16 pending_write_addr;
|
|
uint16 pending_write_latch;
|
|
|
|
uint8 status;
|
|
|
|
uint16 SAT[0x100];
|
|
|
|
uint16 VRAM[65536]; //VRAM_Size];
|
|
|
|
union {
|
|
uint64 bg_tile_cache64[65536 / 16][8]; // Tile, y, x
|
|
uint8 bg_tile_cache[65536 / 16][8][8];
|
|
};
|
|
|
|
uint16 DMAReadBuffer;
|
|
bool DMAReadWrite;
|
|
bool DMARunning;
|
|
bool DMAPending;
|
|
bool SATBPending;
|
|
bool burst_mode;
|
|
|
|
uint32 BG_YOffset; // Reloaded from BYR at start of display area?
|
|
uint32 BG_XOffset; // Reloaded from BXR at each scanline, methinks.
|
|
|
|
uint32 HSW_cache, HDS_cache, HDW_cache, HDE_cache;
|
|
|
|
uint32 VDS_cache;
|
|
uint32 VSW_cache;
|
|
uint32 VDW_cache;
|
|
uint32 VCR_cache;
|
|
uint16 MWR_cache;
|
|
|
|
uint32 BG_YMoo;
|
|
bool NeedRCRInc, NeedVBIRQTest, NeedSATDMATest, NeedBGYInc;
|
|
int HPhase, VPhase;
|
|
int32 HPhaseCounter, VPhaseCounter;
|
|
|
|
int32 sprite_cg_fetch_counter;
|
|
|
|
int32 mystery_counter;
|
|
bool mystery_phase;
|
|
|
|
uint16 linebuf[1024 + 512];
|
|
uint32 pixel_desu;
|
|
int32 pixel_copy_count;
|
|
uint32 userle; // User layer enable.
|
|
bool unlimited_sprites;
|
|
|
|
int active_sprites;
|
|
SPRLE SpriteList[64 * 2]; // (see unlimited_sprites option, *2 to accommodate 32-pixel-width sprites ) //16];
|
|
};
|
|
|
|
#endif
|