BizHawk/waterbox/pcfx/huc6270/vdc.h

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