1 #ifndef __PCE_VDC_H 2 #define __PCE_VDC_H 3 4 #include <mednafen/lepacker.h> 5 6 namespace Mednafen 7 { 8 9 #define VDC_PIXEL_OUT_MASK 0x01FF 10 11 // This bit will be set for a non-sprite pixel if the BG layer is disabled(via ToggleLayer()), 12 #define VDC_BGDISABLE_OUT_MASK 0x0200 13 14 // HSync and VSync out bits are only valid when the EX bits in VDC's CR 15 // are set so that the VDC will output sync signals rather than 16 // input them. If it is not configured in this manner, the bit(s) shall always be 0. 17 #define VDC_HSYNC_OUT_MASK 0x2000 18 #define VDC_VSYNC_OUT_MASK 0x4000 19 20 // The DISP bit can either denote active display area(1 = active, 0 = inactive), 21 // colorburst insertion period(0 = insert colorburst, 1 = not in colorburst period; may not be emulated correctly), 22 // or "internal horizontal synchronous signal"(may not be emulated correctly), depending on the TE 23 // bits in the VDC's CR. 24 #define VDC_DISP_OUT_MASK 0x8000 25 26 #define VDC_REGSETP(_reg, _data, _msb) { _reg &= 0xFF << ((_msb) ? 0 : 8); _reg |= (_data) << ((_msb) ? 8 : 0); } 27 #define VDC_REGGETP(_reg, _msb) ((_reg >> ((_msb) ? 8 : 0)) & 0xFF) 28 29 static const unsigned int vram_inc_tab[4] = { 1, 32, 64, 128 }; 30 31 #define VDC_IS_BSY (pending_read || pending_write) 32 33 typedef struct 34 { 35 uint32 x; 36 uint32 flags; 37 uint8 palette_index; 38 uint16 pattern_data[4]; 39 } SPRLE; 40 41 typedef struct 42 { 43 // In the case the VDC access doesn't cause a VRAM read/write, only ReadCount/WriteCount will be set to 0. 44 uint32 ReadStart; 45 uint32 ReadCount; 46 uint32 WriteStart; 47 uint32 WriteCount; 48 49 uint32 RegRWIndex; 50 bool RegWriteDone; 51 bool RegReadDone; 52 } VDC_SimulateResult; 53 54 class VDC 55 { 56 public: 57 58 VDC() MDFN_COLD; 59 ~VDC() MDFN_COLD; 60 61 // Default false. 62 void SetUnlimitedSprites(const bool nospritelimit); 63 64 // The VRAM size is specified in 16-bit words. Default 65536. 65 // Reset() should be called after changing this setting, otherwise things may be broken. 66 void SetVRAMSize(const uint32 par_VRAM_size); 67 68 int32 Reset(void) MDFN_WARN_UNUSED_RESULT; 69 70 // ResetSimulate(), SimulateWrite(), and SimulateRead() are intended to handle VRAM read/write breakpoints. 71 // SimulateWrite() and SimulateRead() will return the VRAM address that will EVENTUALLY be written(upper 32-bits) and/or read(lower 32-bits) to 72 // due to the access, or 0xFFFFFFFF in the upper or lower 32-bits if no VRAM access of that type occurs. 73 // 74 // 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() 75 // or SimulateWrite() alternates(even if just once) between the data port high byte and control port between calls to ResetSimulate() 76 // Call to reset simulation state. 77 78 ResetSimulate(void)79 INLINE void ResetSimulate(void) 80 { 81 Simulate_MAWR = MAWR; 82 Simulate_MARR = MARR; 83 84 Simulate_select = select; 85 Simulate_CR = CR; 86 87 Simulate_LENR = LENR; 88 } 89 SimulateRead(uint32 A,VDC_SimulateResult * result)90 INLINE void SimulateRead(uint32 A, VDC_SimulateResult *result) 91 { 92 result->ReadCount = 0; 93 result->WriteCount = 0; 94 result->RegReadDone = false; 95 result->RegWriteDone = false; 96 97 if(A & 0x2) 98 { 99 result->RegReadDone = true; 100 result->RegRWIndex = Simulate_select; 101 } 102 103 if((A & 0x3) == 0x3 && Simulate_select == 0x02) 104 { 105 Simulate_MARR += vram_inc_tab[(Simulate_CR >> 11) & 0x3]; 106 107 result->ReadStart = Simulate_MARR; 108 result->ReadCount = 1; 109 } 110 } 111 SimulateWrite(uint32 A,uint8 V,VDC_SimulateResult * result)112 INLINE void SimulateWrite(uint32 A, uint8 V, VDC_SimulateResult *result) 113 { 114 result->ReadCount = 0; 115 result->WriteCount = 0; 116 result->RegReadDone = false; 117 result->RegWriteDone = false; 118 119 const unsigned int msb = A & 1; 120 121 switch(A & 0x3) 122 { 123 case 0x00: Simulate_select = V & 0x1F; 124 break; 125 126 case 0x02: 127 case 0x03: 128 result->RegWriteDone = true; 129 result->RegRWIndex = Simulate_select; 130 131 switch(Simulate_select) 132 { 133 case 0x00: VDC_REGSETP(Simulate_MAWR, V, msb); 134 break; 135 136 case 0x01: VDC_REGSETP(Simulate_MARR, V, msb); 137 Simulate_MARR += vram_inc_tab[(Simulate_CR >> 11) & 0x3]; 138 139 result->ReadStart = Simulate_MARR; 140 result->ReadCount = 1; 141 break; 142 143 case 0x02: if(msb) 144 { 145 result->WriteStart = Simulate_MAWR; 146 result->WriteCount = 1; 147 148 Simulate_MAWR += vram_inc_tab[(Simulate_CR >> 11) & 0x3]; 149 } 150 break; 151 152 case 0x12: VDC_REGSETP(Simulate_LENR, V, msb); 153 if(msb) 154 { 155 result->ReadStart = SOUR; 156 result->ReadCount = Simulate_LENR + 1; 157 158 if(DCR & 0x4) 159 result->ReadStart = (result->ReadStart - (result->ReadCount - 1)) & 0xFFFF; 160 161 result->WriteStart = DESR; 162 result->WriteCount = Simulate_LENR + 1; 163 164 if(DCR & 0x8) 165 result->WriteStart = (result->WriteStart - (result->WriteCount - 1)) & 0xFFFF; 166 } 167 break; 168 169 } 170 break; 171 } 172 } 173 SimulateRead16(bool A,VDC_SimulateResult * result)174 INLINE void SimulateRead16(bool A, VDC_SimulateResult *result) 175 { 176 result->ReadCount = 0; 177 result->WriteCount = 0; 178 result->RegReadDone = false; 179 result->RegWriteDone = false; 180 181 if(A & 0x2) 182 { 183 result->RegReadDone = true; 184 result->RegRWIndex = Simulate_select; 185 } 186 187 if(A && Simulate_select == 0x02) 188 { 189 Simulate_MARR += vram_inc_tab[(Simulate_CR >> 11) & 0x3]; 190 191 result->ReadStart = Simulate_MARR; 192 result->ReadCount = 1; 193 } 194 } 195 196 SimulateWrite16(bool A,uint16 V,VDC_SimulateResult * result)197 INLINE void SimulateWrite16(bool A, uint16 V, VDC_SimulateResult *result) 198 { 199 result->ReadCount = 0; 200 result->WriteCount = 0; 201 result->RegReadDone = false; 202 result->RegWriteDone = false; 203 204 if(!A) 205 Simulate_select = V & 0x1F; 206 else 207 { 208 result->RegWriteDone = true; 209 result->RegRWIndex = Simulate_select; 210 211 switch(Simulate_select) 212 { 213 case 0x00: Simulate_MAWR = V; 214 break; 215 216 case 0x01: Simulate_MARR = V; 217 Simulate_MARR += vram_inc_tab[(Simulate_CR >> 11) & 0x3]; 218 219 result->ReadStart = Simulate_MARR; 220 result->ReadCount = 1; 221 break; 222 223 case 0x02: result->WriteStart = Simulate_MAWR; 224 result->WriteCount = 1; 225 226 Simulate_MAWR += vram_inc_tab[(Simulate_CR >> 11) & 0x3]; 227 break; 228 229 case 0x12: Simulate_LENR = V; 230 result->ReadStart = SOUR; 231 result->ReadCount = Simulate_LENR + 1; 232 233 if(DCR & 0x4) 234 result->ReadStart = (result->ReadStart - (result->ReadCount - 1)) & 0xFFFF; 235 236 result->WriteStart = DESR; 237 result->WriteCount = Simulate_LENR + 1; 238 239 if(DCR & 0x8) 240 result->WriteStart = (result->WriteStart - (result->WriteCount - 1)) & 0xFFFF; 241 break; 242 243 } 244 } 245 } 246 247 248 int32 HSync(bool); 249 int32 VSync(bool); 250 251 252 void Write(uint32 A, uint8 V, int32 &next_event); 253 uint8 Read(uint32 A, int32 &next_event, bool peek = false); 254 255 void Write16(bool A, uint16 V); 256 uint16 Read16(bool A, bool peek = false); 257 258 int32 Run(int32 clocks, /*bool hs, bool vs,*/ uint16 *pixels, bool skip); 259 260 261 void FixTileCache(uint16); 262 void SetLayerEnableMask(uint64 mask); 263 264 void RunDMA(int32, bool force_completion = false); 265 void RunSATDMA(int32, bool force_completion = false); 266 267 void IncRCR(void); 268 void DoVBIRQTest(void); 269 void HDS_Start(void); 270 271 void StateExtra(LEPacker &sl_packer, bool load); 272 void StateAction(StateMem *sm, const unsigned load, const bool data_only, const char *sname); 273 274 // Peek(VRAM/SAT) and Poke(VRAM/SAT) work in 16-bit VRAM word units. PeekVRAM(uint16 Address)275 INLINE uint16 PeekVRAM(uint16 Address) 276 { 277 if(Address < VRAM_Size) 278 return(VRAM[Address]); 279 else 280 return(0); 281 } 282 PeekSAT(uint8 Address)283 INLINE uint16 PeekSAT(uint8 Address) 284 { 285 return(SAT[Address]); 286 } 287 PokeVRAM(uint16 Address,const uint16 Data)288 INLINE void PokeVRAM(uint16 Address, const uint16 Data) 289 { 290 if(Address < VRAM_Size) 291 { 292 VRAM[Address] = Data; 293 FixTileCache(Address); 294 } 295 } 296 PokeSAT(uint8 Address,const uint16 Data)297 INLINE void PokeSAT(uint8 Address, const uint16 Data) 298 { 299 SAT[Address] = Data; 300 } 301 302 303 // Register enums for GetRegister() and SetRegister() 304 enum 305 { 306 GSREG_MAWR = 0, 307 GSREG_MARR, 308 GSREG_CR, 309 GSREG_RCR, 310 GSREG_BXR, 311 GSREG_BYR, 312 GSREG_MWR, 313 GSREG_HSR, 314 GSREG_HDR, 315 GSREG_VSR, 316 GSREG_VDR, 317 GSREG_VCR, 318 GSREG_DCR, 319 GSREG_SOUR, 320 GSREG_DESR, 321 GSREG_LENR, 322 GSREG_DVSSR, 323 324 GSREG_SELECT, 325 GSREG_STATUS, 326 327 __GSREG_COUNT 328 }; 329 330 // Pass NULL if you don't want more information about the special meaning of the value in the specified 331 // register. Otherwise, pass a buffer of at least 256 bytes in size. 332 uint32 GetRegister(const unsigned int id, char *special, const uint32 special_len); 333 void SetRegister(const unsigned int id, const uint32 value); 334 335 #ifdef WANT_DEBUGGER 336 bool DoGfxDecode(uint32 *target, const uint32 *color_table, const uint32 TransparentColor, bool DecodeSprites, 337 int32 w, int32 h, int32 scroll); 338 #endif 339 PeekIRQ(void)340 INLINE bool PeekIRQ(void) 341 { 342 return((bool)(status & 0x3F)); 343 } 344 SetIRQHook(void (* irqh)(bool))345 INLINE void SetIRQHook(void (*irqh)(bool)) 346 { 347 IRQHook = irqh; 348 } 349 SetWSHook(bool (* wsh)(int32))350 INLINE void SetWSHook(bool (*wsh)(int32)) 351 { 352 WSHook = wsh; 353 } 354 355 private: 356 357 int TimeFromHDSStartToBYRLatch(void); 358 int TimeFromBYRLatchToBXRLatch(void); 359 360 enum 361 { 362 HPHASE_HDS = 0, 363 HPHASE_HDS_PART2, 364 HPHASE_HDS_PART3, 365 HPHASE_HDW, 366 HPHASE_HDW_FINAL, 367 HPHASE_HDE, 368 HPHASE_HSW, 369 HPHASE_COUNT 370 }; 371 372 enum 373 { 374 VPHASE_VDS = 0, 375 VPHASE_VDW, 376 VPHASE_VCR, 377 VPHASE_VSW, 378 VPHASE_COUNT 379 }; 380 381 int VRAM_Size; // = 0x8000; 382 int VRAM_SizeMask; // = VRAM_Size - 1; //0x7FFF; 383 int VRAM_BGTileNoMask; // = VRAM_SizeMask / 16; //0x7FF; 384 385 void (*IRQHook)(bool); 386 bool (*WSHook)(int32); 387 388 void DoWaitStates(void); 389 void CheckAndCommitPending(void); 390 CalcNextEvent(void)391 INLINE int32 CalcNextEvent(void) 392 { 393 int32 next_event = HPhaseCounter; 394 395 if(sat_dma_counter > 0 && sat_dma_counter < next_event) 396 next_event = sat_dma_counter; 397 398 if(sprite_cg_fetch_counter > 0 && sprite_cg_fetch_counter < next_event) 399 next_event = sprite_cg_fetch_counter; 400 401 if(DMARunning) 402 { 403 assert(VDMA_CycleCounter < 2); 404 405 int32 next_vram_dma_event = ((LENR + 1) * 4) - (DMAReadWrite * 2) - VDMA_CycleCounter; 406 407 assert(next_vram_dma_event > 0); 408 409 if(next_vram_dma_event > 0 && next_vram_dma_event < next_event) 410 next_event = next_vram_dma_event; 411 412 //printf("Next VRAM DMA event: %d(LENR = %d)\n", next_vram_dma_event, LENR); 413 } 414 415 assert(next_event > 0); 416 return(next_event); 417 } 418 419 bool in_exhsync, in_exvsync; 420 421 void CalcWidthStartEnd(uint32 &display_width, uint32 &start, uint32 &end); 422 void DrawBG(uint16 *target, int enabled); 423 void DrawSprites(uint16 *target, int enabled); 424 void FetchSpriteData(void); 425 426 427 uint8 Simulate_select; 428 uint16 Simulate_MAWR; 429 uint16 Simulate_MARR; 430 uint16 Simulate_CR; 431 uint16 Simulate_LENR; 432 433 int32 sat_dma_counter; 434 435 uint8 select; 436 uint16 MAWR; // Memory Address Write Register 437 uint16 MARR; // Memory Address Read Register 438 439 uint16 CR; // Control Register 440 uint16 CR_cache; // Cache for BG/SPR enable 441 uint16 RCR; // Raster Compare Register 442 uint16 BXR; // Background X-Scroll Register 443 uint16 BYR; // Background Y-Scroll Register 444 uint16 MWR; // Memory Width Register 445 446 uint16 HSR; // Horizontal Sync Register 447 uint16 HDR; // Horizontal Display Register 448 uint16 VSR; 449 uint16 VDR; 450 451 uint16 VCR; 452 uint16 DCR; 453 uint16 SOUR; 454 uint16 DESR; 455 uint16 LENR; 456 uint16 DVSSR; 457 458 // Internal SAT DMA transfer variables. 459 //uint16 SAT_SOUR; 460 //uint16 SAT_DESR; 461 //uint16 SAT_LENR; 462 463 int32 VDMA_CycleCounter; 464 465 uint32 RCRCount; 466 467 bool pending_read; 468 uint16 pending_read_addr; 469 uint16 read_buffer; 470 471 uint8 write_latch; // LSB 472 473 bool pending_write; 474 uint16 pending_write_addr; 475 uint16 pending_write_latch; 476 477 uint8 status; 478 479 uint16 SAT[0x100]; 480 481 uint16 VRAM[65536]; //VRAM_Size]; 482 483 union 484 { 485 uint64 bg_tile_cache64[65536 / 16][8]; // Tile, y, x 486 uint8 bg_tile_cache[65536 / 16][8][8]; 487 }; 488 489 uint16 DMAReadBuffer; 490 bool DMAReadWrite; 491 bool DMARunning; 492 bool DMAPending; 493 bool SATBPending; 494 bool burst_mode; 495 496 uint32 BG_YOffset; // Reloaded from BYR at start of display area? 497 uint32 BG_XOffset; // Reloaded from BXR at each scanline, methinks. 498 499 uint32 HSW_cache, HDS_cache, HDW_cache, HDE_cache; 500 501 uint32 VDS_cache; 502 uint32 VSW_cache; 503 uint32 VDW_cache; 504 uint32 VCR_cache; 505 uint16 MWR_cache; 506 507 508 uint32 BG_YMoo; 509 bool NeedRCRInc, NeedVBIRQTest, NeedSATDMATest, NeedBGYInc; 510 int HPhase, VPhase; 511 int32 HPhaseCounter, VPhaseCounter; 512 513 int32 sprite_cg_fetch_counter; 514 515 516 int32 mystery_counter; 517 bool mystery_phase; 518 519 uint16 linebuf[1024 + 512]; 520 uint32 pixel_desu; 521 int32 pixel_copy_count; 522 uint32 userle; // User layer enable. 523 bool unlimited_sprites; 524 525 int active_sprites; 526 SPRLE SpriteList[64 * 2]; // (see unlimited_sprites option, *2 to accommodate 32-pixel-width sprites ) //16]; 527 }; 528 529 } 530 #endif 531