/******************************************************************************/ /* Mednafen Sega Saturn Emulation Module */ /******************************************************************************/ /* vdp2.cpp - VDP2 Emulation ** Copyright (C) 2015-2016 Mednafen Team ** ** This program 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 2 ** of the License, or (at your option) any later version. ** ** This program 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 this program; if not, write to the Free Software Foundation, Inc., ** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // TODO: Emulate brokenness(missing vblank) that occurs when switching from 240-height mode to 224-height mode around lines 224-239. // TODO: Update output signals on Reset()? Might have to call VDP2::Reset() before other _Reset() then...and take special care in the // SMPC clock change code. #include "ss.h" #include "vdp1.h" #include "vdp2.h" #include "scu.h" #include "smpc.h" #include "vdp2_common.h" #include "vdp2_render.h" namespace MDFN_IEN_SS { namespace VDP2 { static bool PAL; static sscpu_timestamp_t lastts; // // // static uint16 RawRegs[0x100]; // For debugging static bool DisplayOn; static bool BorderMode; static bool ExLatchEnable; static bool ExSyncEnable; static bool ExBGEnable; static bool DispAreaSelect; static bool VRAMSize; static uint8 HRes, VRes; static uint8 InterlaceMode; enum { IM_NONE, IM_ILLEGAL, IM_SINGLE, IM_DOUBLE }; static uint16 RAMCTL_Raw; static uint8 CRAM_Mode; enum { CRAM_MODE_RGB555_1024 = 0, CRAM_MODE_RGB555_2048 = 1, CRAM_MODE_RGB888_1024 = 2, CRAM_MODE_ILLEGAL = 3 }; static uint16 BGON; static uint8 VCPRegs[4][8]; static uint32 VRAMPenalty[4]; static uint32 RPTA; static uint8 RPRCTL[2]; static uint8 KTAOF[2]; static uint16 VRAM[262144]; static uint16 CRAM[2048]; static struct { // Signed values are stored sign-extended to the full 32 bits. int32 Xst, Yst, Zst; // 1.12.10 int32 DXst, DYst; // 1. 2.10 int32 DX, DY; // 1. 2.10 int32 RotMatrix[6]; // 1. 3.10 int32 Px, Py, Pz; // 1.13. 0 int32 Cx, Cy, Cz; // 1.13. 0 int32 Mx, My; // 1.13.10 int32 kx, ky; // 1. 7.16 uint32 KAst; // 0.16.10 uint32 DKAst; // 1. 9.10 uint32 DKAx; // 1. 9.10 // // // uint32 XstAccum, YstAccum; // 1.12.10 (sorta) uint32 KAstAccum; // .10 } RotParams[2]; static void FetchRotParams(const bool field) { uint32 a = RPTA & 0x7FFBE; for(unsigned i = 0; i < 2; i++) { auto& rp = RotParams[i]; rp.Xst = sign_x_to_s32(23, ne16_rbo_be(VRAM, ((a + 0x00) & 0x3FFFF) << 1) >> 6); rp.Yst = sign_x_to_s32(23, ne16_rbo_be(VRAM, ((a + 0x02) & 0x3FFFF) << 1) >> 6); rp.Zst = sign_x_to_s32(23, ne16_rbo_be(VRAM, ((a + 0x04) & 0x3FFFF) << 1) >> 6); rp.DXst = sign_x_to_s32(13, ne16_rbo_be(VRAM, ((a + 0x06) & 0x3FFFF) << 1) >> 6); rp.DYst = sign_x_to_s32(13, ne16_rbo_be(VRAM, ((a + 0x08) & 0x3FFFF) << 1) >> 6); rp.DX = sign_x_to_s32(13, ne16_rbo_be(VRAM, ((a + 0x0A) & 0x3FFFF) << 1) >> 6); rp.DY = sign_x_to_s32(13, ne16_rbo_be(VRAM, ((a + 0x0C) & 0x3FFFF) << 1) >> 6); for(unsigned m = 0; m < 6; m++) { rp.RotMatrix[m] = sign_x_to_s32(14, ne16_rbo_be(VRAM, ((a + 0x0E + (m << 1)) & 0x3FFFF) << 1) >> 6); } rp.Px = sign_x_to_s32(14, VRAM[(a + 0x1A) & 0x3FFFF]); rp.Py = sign_x_to_s32(14, VRAM[(a + 0x1B) & 0x3FFFF]); rp.Pz = sign_x_to_s32(14, VRAM[(a + 0x1C) & 0x3FFFF]); rp.Cx = sign_x_to_s32(14, VRAM[(a + 0x1E) & 0x3FFFF]); rp.Cy = sign_x_to_s32(14, VRAM[(a + 0x1F) & 0x3FFFF]); rp.Cz = sign_x_to_s32(14, VRAM[(a + 0x20) & 0x3FFFF]); rp.Mx = sign_x_to_s32(24, ne16_rbo_be(VRAM, ((a + 0x22) & 0x3FFFF) << 1) >> 6); rp.My = sign_x_to_s32(24, ne16_rbo_be(VRAM, ((a + 0x24) & 0x3FFFF) << 1) >> 6); rp.kx = sign_x_to_s32(24, ne16_rbo_be(VRAM, ((a + 0x26) & 0x3FFFF) << 1)); rp.ky = sign_x_to_s32(24, ne16_rbo_be(VRAM, ((a + 0x28) & 0x3FFFF) << 1)); rp.KAst = ne16_rbo_be(VRAM, ((a + 0x2A) & 0x3FFFF) << 1) >> 6; rp.DKAst = sign_x_to_s32(20, ne16_rbo_be(VRAM, ((a + 0x2C) & 0x3FFFF) << 1) >> 6); rp.DKAx = sign_x_to_s32(20, ne16_rbo_be(VRAM, ((a + 0x2E) & 0x3FFFF) << 1) >> 6); a += 0x40; // // Interlace mode doesn't seem to affect operation? // // const bool imft = (InterlaceMode == IM_DOUBLE && field); if(RPRCTL[i] & 0x01) rp.XstAccum = rp.Xst; // + rp.DXst * imft; else rp.XstAccum += rp.DXst; // << (InterlaceMode == IM_DOUBLE); if(RPRCTL[i] & 0x02) rp.YstAccum = rp.Yst; // + rp.DYst * imft; else rp.YstAccum += rp.DYst; // << (InterlaceMode == IM_DOUBLE); if(RPRCTL[i] & 0x04) rp.KAstAccum = (KTAOF[i] << 26) + rp.KAst; // + rp.DKAst * imft; else rp.KAstAccum += rp.DKAst; // << (InterlaceMode == IM_DOUBLE); } } enum { VPHASE_ACTIVE = 0, VPHASE_BOTTOM_BORDER, VPHASE_BOTTOM_BLANKING, VPHASE_VSYNC, VPHASE_TOP_BLANKING, VPHASE_TOP_BORDER, VPHASE__COUNT }; static const int32 VTimings[2][4][VPHASE__COUNT] = // End lines { { // NTSC: { 0x0E0, 0xE8, 0xED, 0xF0, 0x0FF, 0x107 }, { 0x0F0, 0xF0, 0xF5, 0xF8, 0x107, 0x107 }, { 0x0E0, 0xE8, 0xED, 0xF0, 0x0FF, 0x107 }, { 0x0F0, 0xF0, 0xF5, 0xF8, 0x107, 0x107 }, }, { // PAL: // btm brdr begin, btm blnk begin, vsync begin, /***/ top blnk begin, top brdr begin, total { 0x0E0, 0x100, 0x103, /***/ 0x103 + 3/*?*/, 0x119, 0x139 }, { 0x0F0, 0x108, 0x10B, /***/ 0x10B + 3/*?*/, 0x121, 0x139 }, { 0x100, 0x110, 0x113, /***/ 0x113 + 3/*?*/, 0x129, 0x139 }, { 0x100, 0x110, 0x113, /***/ 0x113 + 3/*?*/, 0x129, 0x139 }, }, }; static bool Out_VB; // VB output signal static uint32 VPhase; /*static*/ int32 VCounter; static bool InternalVB; static bool Odd; // static int SurfInterlaceField; // // // // (No 0) 8 accesses, No split: 0 added cycles // (No 4) 4 accesses, No split: 1 added cycles // (No 6) 2 accesses, No split: 2 added cycles // (No 7) 1 accesses, No split: 3, Split: 3.51? added cycles // (No 8) 0 accesses, No split: 4, Split: 5.34? added cycles static INLINE void RecalcVRAMPenalty(void) { if(InternalVB) VRAMPenalty[0] = VRAMPenalty[1] = VRAMPenalty[2] = VRAMPenalty[3] = 0; else { const unsigned VRAM_Mode = (RAMCTL_Raw >> 8) & 0x3; const unsigned RDBS_Mode = (RAMCTL_Raw & 0xFF); const size_t sh = ((HRes & 0x6) ? 0 : 4); uint8 vcp_type_penalty[0x10]; for(unsigned vcp_type = 0; vcp_type < 0x10; vcp_type++) { bool penalty; if((vcp_type < 0x8) || vcp_type == 0xC || vcp_type == 0xD) penalty = (bool)(BGON & (1U << (vcp_type & 0x3))); else penalty = false; vcp_type_penalty[vcp_type] = penalty; } for(unsigned bank = 0; bank < 4; bank++) { const unsigned esb = bank & (2 | ((VRAM_Mode >> (bank >> 1)) & 1)); const uint8 rdbs = (RDBS_Mode >> (esb << 1)) & 0x3; uint32 tmp = 0; if(BGON & 0x20) { if(bank >= 2 || ((BGON & 0x10) && rdbs != RDBS_UNUSED)) tmp = 8; } else { if((BGON & 0x10) && rdbs != RDBS_UNUSED) tmp = 8; else if(BGON & 0x0F) { tmp += vcp_type_penalty[VCPRegs[esb][0]]; tmp += vcp_type_penalty[VCPRegs[esb][1]]; tmp += vcp_type_penalty[VCPRegs[esb][2]]; tmp += vcp_type_penalty[VCPRegs[esb][3]]; tmp += vcp_type_penalty[VCPRegs[esb][sh + 0]]; tmp += vcp_type_penalty[VCPRegs[esb][sh + 1]]; tmp += vcp_type_penalty[VCPRegs[esb][sh + 2]]; tmp += vcp_type_penalty[VCPRegs[esb][sh + 3]]; } } static const uint8 tab[9] = { 0, 0, 0, 0, 1, 1, 2, 3, 4 }; VRAMPenalty[bank] = tab[tmp]; //printf("%d, %d\n", bank, tmp); } } } enum { HPHASE_ACTIVE = 0, HPHASE_RIGHT_BORDER, HPHASE_HSYNC, // ... ? ? ? HPHASE__COUNT }; static const int32 HTimings[2][HPHASE__COUNT] = { { 0x140, 0x15B, 0x1AB }, { 0x160, 0x177, 0x1C7 }, }; static uint32 HPhase; /*static*/ int32 HCounter; static uint16 Latched_VCNT, Latched_HCNT; static bool HVIsExLatched; static void LatchHV(void) { { unsigned vtmp; if(VPhase >= VPHASE_VSYNC) vtmp = VCounter + (0x200 - VTimings[PAL][VRes][VPHASE__COUNT - 1]); else vtmp = VCounter; if(InterlaceMode == IM_DOUBLE) vtmp = (vtmp << 1) | !Odd; Latched_VCNT = vtmp; } if(HPhase >= HPHASE_HSYNC) Latched_HCNT = (HCounter + (0x200 - HTimings[HRes & 1][HPHASE__COUNT - 1])) << 1; else Latched_HCNT = HCounter << 1; //HVIsLatched = true; // Only on external signal-induced latching? } // // void StartFrame(EmulateSpecStruct* espec, const bool clock28m) { //printf("StartFrame: %d\n", SurfInterlaceField); VDP2REND_StartFrame(espec, clock28m, SurfInterlaceField); } // // static INLINE void IncVCounter(const sscpu_timestamp_t event_timestamp) { VCounter = (VCounter + 1) & 0x1FF; if(VCounter == (VTimings[PAL][VRes][VPHASE__COUNT - 1] - 1)) Out_VB = false; // - 1, so the CPU loop will have plenty of time to exit before we reach non-hblank top border area // (exit granularity could be large if program is executing from SCSP RAM space, for example). if(VCounter == (VTimings[PAL][VRes][VPHASE_TOP_BLANKING] - 1)) { #if 0 for(unsigned bank = 0; bank < 4; bank++) { printf("Bank %d: ", bank); for(unsigned vc = 0; vc < 8; vc++) printf("%01x ", VCPRegs[bank][vc]); printf("\n"); } #endif SS_RequestMLExit(); VDP2REND_EndFrame(); //printf("Meow: %d\n", VCounter); } while(VCounter >= VTimings[PAL][VRes][VPhase] - ((VPhase == VPHASE_VSYNC - 1) && InterlaceMode)) { VPhase++; if(VPhase == VPHASE__COUNT) { VPhase = 0; VCounter -= VTimings[PAL][VRes][VPHASE__COUNT - 1]; } if(VPhase == VPHASE_ACTIVE) InternalVB = !DisplayOn; else if(VPhase == VPHASE_BOTTOM_BORDER) { SS_SetEventNT(&events[SS_EVENT_MIDSYNC], event_timestamp + 1); InternalVB = true; Out_VB = true; } else if(VPhase == VPHASE_VSYNC) { if(InterlaceMode) { Odd = !Odd; VCounter += Odd; SurfInterlaceField = !Odd; } else { SurfInterlaceField = -1; Odd = true; } } } RecalcVRAMPenalty(); SMPC_SetVB(event_timestamp, Out_VB); } static INLINE int32 AddHCounter(const sscpu_timestamp_t event_timestamp, int32 count) { HCounter += count; //if(HCounter > HTimings[HRes & 1][HPhase]) // printf("VDP2 oops: %d %d\n", HCounter, HTimings[HRes & 1][HPhase]); while(HCounter >= HTimings[HRes & 1][HPhase]) { HPhase++; if(HPhase == HPHASE__COUNT) { HPhase = 0; HCounter -= HTimings[HRes & 1][HPHASE__COUNT - 1]; } // // // if(HPhase == HPHASE_ACTIVE) { if(VPhase == VPHASE_ACTIVE) { VDP2Rend_LIB* lib = VDP2REND_GetLIB(VCounter); if(!InternalVB) { if(BGON & 0x30) { if(VCounter == 0) RPRCTL[0] = RPRCTL[1] = 0x07; FetchRotParams(false/*field*/); RPRCTL[0] = RPRCTL[1] = 0; } for(unsigned i = 0; i < 2; i++) { auto const& rp = RotParams[i]; auto& r = lib->rv[i]; r.Xsp = ((int64)rp.RotMatrix[0] * ((int32)rp.XstAccum - (rp.Px * 1024)) + (int64)rp.RotMatrix[1] * ((int32)rp.YstAccum - (rp.Py * 1024)) + (int64)rp.RotMatrix[2] * (rp.Zst - (rp.Pz * 1024))) >> 10; r.Ysp = ((int64)rp.RotMatrix[3] * ((int32)rp.XstAccum - (rp.Px * 1024)) + (int64)rp.RotMatrix[4] * ((int32)rp.YstAccum - (rp.Py * 1024)) + (int64)rp.RotMatrix[5] * (rp.Zst - (rp.Pz * 1024))) >> 10; r.Xp = rp.RotMatrix[0] * (rp.Px - rp.Cx) + rp.RotMatrix[1] * (rp.Py - rp.Cy) + rp.RotMatrix[2] * (rp.Pz - rp.Cz) + (rp.Cx * 1024) + rp.Mx; r.Yp = rp.RotMatrix[3] * (rp.Px - rp.Cx) + rp.RotMatrix[4] * (rp.Py - rp.Cy) + rp.RotMatrix[5] * (rp.Pz - rp.Cz) + (rp.Cy * 1024) + rp.My; r.dX = (rp.RotMatrix[0] * rp.DX + rp.RotMatrix[1] * rp.DY) >> 10; r.dY = (rp.RotMatrix[3] * rp.DX + rp.RotMatrix[4] * rp.DY) >> 10; r.kx = rp.kx; r.ky = rp.ky; r.KAstAccum = rp.KAstAccum; r.DKAx = rp.DKAx; } } //printf("%d, 0x%08x(%f) 0x%08x(%f)\n", VCounter, RotParams[0].KAstAccum >> 10, (int32)RotParams[0].DKAst / 1024.0, RotParams[1].KAstAccum >> 10, (int32)RotParams[1].DKAst / 1024.0); //printf("DL: %d\n", VCounter); lib->vdp1_hires8 = VDP1::GetLine(VCounter, lib->vdp1_line, (HRes & 1) ? 352 : 320, (int32)RotParams[0].XstAccum >> 1, (int32)RotParams[0].YstAccum >> 1, (int32)RotParams[0].DX >> 1, (int32)RotParams[0].DY >> 1); // Always call, has side effects. VDP2REND_DrawLine(InternalVB ? -1 : VCounter, !Odd); } else if(VPhase == VPHASE_TOP_BORDER || VPhase == VPHASE_BOTTOM_BORDER) VDP2REND_DrawLine(-1, !Odd); } else if(HPhase == HPHASE_HSYNC) { IncVCounter(event_timestamp); } } return (HTimings[HRes & 1][HPhase] - HCounter); } sscpu_timestamp_t Update(sscpu_timestamp_t timestamp) { int32 clocks = (timestamp - lastts) >> 2; if(MDFN_UNLIKELY(timestamp < lastts)) { SS_DBGTI(SS_DBG_WARNING | SS_DBG_VDP2, "[VDP2] [BUG] timestamp(%d) < lastts(%d)", timestamp, lastts); clocks = 0; } lastts += clocks << 2; // // int32 ne; int32 tmp; ne = AddHCounter(timestamp, clocks); VDP1::SetHBVB(timestamp, HPhase > HPHASE_ACTIVE, Out_VB); tmp = SCU_SetHBVB(clocks, HPhase > HPHASE_ACTIVE, Out_VB); if(tmp < ne) ne = tmp; return lastts + (ne << 2); } // // Register writes seem to always be 16-bit // static INLINE void RegsWrite(uint32 A, uint16 V) { A &= 0x1FE; RawRegs[A >> 1] = V; SS_DBGTI(SS_DBG_VDP2_REGW, "[VDP2] Register write 0x%03x: 0x%04x", A, V); switch(A) { default: // SS_DBGTI(SS_DBG_WARNING | SS_DBG_VDP2, "[VDP2] Unknown write to register at 0x%08x of value 0x%04x", A, V); break; case 0x00: Update(SH7095_mem_timestamp); // DisplayOn = (V >> 15) & 0x1; BorderMode = (V >> 8) & 0x1; InterlaceMode = (V >> 6) & 0x3; VRes = (V >> 4) & 0x3; HRes = (V >> 0) & 0x7; // InternalVB |= !DisplayOn; // SS_SetEventNT(&events[SS_EVENT_VDP2], Update(SH7095_mem_timestamp)); break; case 0x02: ExLatchEnable = (V >> 9) & 0x1; ExSyncEnable = (V >> 8) & 0x1; DispAreaSelect = (V >> 1) & 0x1; ExBGEnable = (V >> 0) & 0x1; break; case 0x06: VRAMSize = (V >> 15) & 0x1; if(VRAMSize) SS_DBGTI(SS_DBG_WARNING | SS_DBG_VDP2, "[VDP2] VRAMSize=%d (unemulated)", VRAMSize); break; case 0x0E: RAMCTL_Raw = V & 0xB3FF; CRAM_Mode = (V >> 12) & 0x3; break; case 0x10: case 0x12: case 0x14: case 0x16: case 0x18: case 0x1A: case 0x1C: case 0x1E: { uint8* const b = &VCPRegs[(A >> 2) & 3][(A & 0x2) << 1]; b[0] = (V >> 12) & 0xF; b[1] = (V >> 8) & 0xF; b[2] = (V >> 4) & 0xF; b[3] = (V >> 0) & 0xF; } break; case 0x20: BGON = V & 0x1F3F; break; case 0xB2: RPRCTL[0] = (V >> 0) & 0x7; RPRCTL[1] = (V >> 8) & 0x7; break; case 0xB6: KTAOF[0] = (V >> 0) & 0x7; KTAOF[1] = (V >> 8) & 0x7; break; case 0xBC: RPTA = (RPTA & 0xFFFF) | ((V & 0x7) << 16); break; case 0xBE: RPTA = (RPTA & ~0xFFFF) | (V & 0xFFFE); break; } } static INLINE uint16 RegsRead(uint32 A) { switch(A & 0x1FE) { default: SS_DBGTI(SS_DBG_WARNING | SS_DBG_VDP2, "[VDP2] Unknown read from 0x%08x", A); return 0; case 0x00: return (DisplayOn << 15) | (BorderMode << 8) | (InterlaceMode << 6) | (VRes << 4) | (HRes << 0); case 0x02: if(!ExLatchEnable) { SS_SetEventNT(&events[SS_EVENT_VDP2], Update(SH7095_mem_timestamp)); LatchHV(); } return (ExLatchEnable << 9) | (ExSyncEnable << 8) | (DispAreaSelect << 1) | (ExBGEnable << 0); case 0x04: SS_SetEventNT(&events[SS_EVENT_VDP2], Update(SH7095_mem_timestamp)); { // TODO: EXSYFG uint16 ret = (HVIsExLatched << 9) | (InternalVB << 3) | ((HPhase > HPHASE_ACTIVE) << 2) | (Odd << 1) | (PAL << 0); HVIsExLatched = false; return ret; } case 0x06: return VRAMSize << 15; case 0x08: return Latched_HCNT; case 0x0A: return Latched_VCNT; case 0x0E: return RAMCTL_Raw; } } template static INLINE uint32 RW(uint32 A, uint16* DB) { static_assert(IsWrite || sizeof(T) == 2, "Wrong type for read."); A &= 0x1FFFFF; // // VRAM // if(A < 0x100000) { const size_t vri = (A & 0x7FFFF) >> 1; if(IsWrite) { const unsigned mask = (sizeof(T) == 2) ? 0xFFFF : (0xFF00 >> ((A & 1) << 3)); VRAM[vri] = (VRAM[vri] &~ mask) | (*DB & mask); } else *DB = VRAM[vri]; return VRAMPenalty[vri >> 16]; } // // CRAM // if(A < 0x180000) { const unsigned cri = (A & 0xFFF) >> 1; if(IsWrite) { switch(CRAM_Mode) { case CRAM_MODE_RGB555_1024: (CRAM + 0x000)[cri & 0x3FF] = *DB; (CRAM + 0x400)[cri & 0x3FF] = *DB; break; case CRAM_MODE_RGB555_2048: CRAM[cri] = *DB; break; case CRAM_MODE_RGB888_1024: case CRAM_MODE_ILLEGAL: default: CRAM[((cri >> 1) & 0x3FF) | ((cri & 1) << 10)] = *DB; break; } } else { switch(CRAM_Mode) { case CRAM_MODE_RGB555_1024: case CRAM_MODE_RGB555_2048: *DB = CRAM[cri]; break; case CRAM_MODE_RGB888_1024: case CRAM_MODE_ILLEGAL: default: *DB = CRAM[((cri >> 1) & 0x3FF) | ((cri & 1) << 10)]; break; } } return 0; } // // Registers // if(A < 0x1C0000) { if(IsWrite) { if(sizeof(T) == 1) SS_DBGTI(SS_DBG_WARNING | SS_DBG_VDP2, "[VDP2] Byte-write to register at 0x%08x(DB=0x%04x)", A, *DB); RegsWrite(A, *DB); } else *DB = RegsRead(A); return 0; } if(IsWrite) { //SS_DBGTI(SS_DBG_WARNING | SS_DBG_VDP2, "[VDP2] Unknown %zu-byte write to 0x%08x(DB=0x%04x)", sizeof(T), A, *DB); } else { //SS_DBGTI(SS_DBG_WARNING | SS_DBG_VDP2, "[VDP2] Unknown %zu-byte read from 0x%08x", sizeof(T), A); *DB = 0; } return 0; } uint16 Read16_DB(uint32 A) { uint16 DB; RW(A, &DB); return DB; } uint32 Write8_DB(uint32 A, uint16 DB) { VDP2REND_Write8_DB(A, DB); return RW(A, &DB); } uint32 Write16_DB(uint32 A, uint16 DB) { VDP2REND_Write16_DB(A, DB); return RW(A, &DB); } // // // void AdjustTS(const int32 delta) { lastts += delta; } void Init(const bool IsPAL) { SurfInterlaceField = -1; PAL = IsPAL; lastts = 0; SS_SetPhysMemMap(0x05E00000, 0x05EFFFFF, VRAM, 0x80000, true); AddMemoryDomain("VDP2 Ram", VRAM, sizeof(VRAM), MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_YUGEENDIAN | MEMORYAREA_FLAGS_WORDSIZE2); AddMemoryDomain("VDP2 CRam", CRAM, sizeof(CRAM), MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_YUGEENDIAN | MEMORYAREA_FLAGS_WORDSIZE2); VDP2REND_Init(IsPAL); } void Reset(bool powering_up) { DisplayOn = false; BorderMode = false; ExLatchEnable = false; ExSyncEnable = false; ExBGEnable = false; DispAreaSelect = false; HRes = 0; VRes = 0; InterlaceMode = 0; VRAMSize = 0; InternalVB = true; Out_VB = false; VPhase = VPHASE_ACTIVE; VCounter = 0; Odd = true; RAMCTL_Raw = 0; CRAM_Mode = 0; BGON = 0; memset(VCPRegs, 0, sizeof(VCPRegs)); for(unsigned i = 0; i < 2; i++) { KTAOF[i] = 0; RPRCTL[i] = 0; } RPTA = 0; memset(RotParams, 0, sizeof(RotParams)); // // FIXME(init values), also in VDP2REND. if(powering_up) { memset(VRAM, 0, sizeof(VRAM)); memset(CRAM, 0, sizeof(CRAM)); } // RecalcVRAMPenalty(); // // VDP2REND_Reset(powering_up); } // // // // uint32 GetRegister(const unsigned id, char* const special, const uint32 special_len) { uint32 ret = 0xDEADBEEF; switch(id) { case GSREG_LINE: ret = VCounter; break; case GSREG_DON: ret = DisplayOn; break; case GSREG_BM: ret = BorderMode; break; case GSREG_IM: ret = InterlaceMode; break; case GSREG_VRES: ret = VRes; break; case GSREG_HRES: ret = HRes; break; } return ret; } void SetRegister(const unsigned id, const uint32 value) { } uint8 PeekVRAM(const uint32 addr) { return ne16_rbo_be(VRAM, addr & 0x7FFFF); } void PokeVRAM(const uint32 addr, const uint8 val) { ne16_wbo_be(VRAM, addr & 0x7FFFF, val); //VDP2REND_Write8_DB(addr, val << (((A & 1) ^ 1) << 3)); } void SetLayerEnableMask(uint64 mask) { VDP2REND_SetLayerEnableMask(mask); } /*void MakeDump(const std::string& path) { FileStream fp(path, FileStream::MODE_WRITE); fp.print_format(" { "); for(unsigned i = 0; i < 0x100; i++) fp.print_format("0x%04x, ", RawRegs[i]); fp.print_format(" }, \n"); fp.print_format(" { "); for(unsigned i = 0; i < 2048; i++) fp.print_format("0x%04x, ", CRAM[i]); fp.print_format(" }, \n"); fp.print_format(" { "); for(unsigned i = 0; i < 0x40000; i++) fp.print_format("0x%04x, ", VRAM[i]); fp.print_format(" }, \n"); fp.close(); }*/ } }