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