1 /******************************************************************************/
2 /* Mednafen Sega Saturn Emulation Module                                      */
3 /******************************************************************************/
4 /* vdp2.cpp - VDP2 Emulation
5 **  Copyright (C) 2015-2019 Mednafen Team
6 **
7 ** This program is free software; you can redistribute it and/or
8 ** modify it under the terms of the GNU General Public License
9 ** as published by the Free Software Foundation; either version 2
10 ** of the License, or (at your option) any later version.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software Foundation, Inc.,
19 ** 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 */
21 
22 // TODO: Emulate brokenness(missing vblank) that occurs when switching from 240-height mode to 224-height mode around lines 224-239.
23 
24 // TODO: Update output signals on Reset()?  Might have to call VDP2::Reset() before other _Reset() then...and take special care in the
25 // SMPC clock change code.
26 
27 #include "ss.h"
28 #include <mednafen/mednafen.h>
29 #include <mednafen/general.h>
30 #include <mednafen/FileStream.h>
31 #include "vdp1.h"
32 #include "vdp2.h"
33 #include "scu.h"
34 #include "smpc.h"
35 
36 #include "vdp2_common.h"
37 #include "vdp2_render.h"
38 
39 namespace MDFN_IEN_SS
40 {
41 #include "sh7095.h"
42 
43 namespace VDP2
44 {
45 
46 static bool PAL;
47 static sscpu_timestamp_t lastts;
48 //
49 //
50 //
51 static uint16 RawRegs[0x100];	// For debugging
52 
53 static bool DisplayOn;
54 static bool BorderMode;
55 bool ExLatchEnable;
56 static bool ExSyncEnable;
57 static bool ExBGEnable;
58 static bool DispAreaSelect;
59 
60 static bool VRAMSize;
61 
62 static uint8 HRes, VRes;
63 static uint8 InterlaceMode;
64 enum { IM_NONE, IM_ILLEGAL, IM_SINGLE, IM_DOUBLE };
65 
66 static uint16 RAMCTL_Raw;
67 static uint8 CRAM_Mode;
68 enum
69 {
70  CRAM_MODE_RGB555_1024	= 0,
71  CRAM_MODE_RGB555_2048	= 1,
72  CRAM_MODE_RGB888_1024	= 2,
73  CRAM_MODE_ILLEGAL	= 3
74 };
75 
76 static uint16 BGON;
77 static uint8 VCPRegs[4][8];
78 static uint32 VRAMPenalty[4];
79 
80 static uint32 RPTA;
81 static uint8 RPRCTL[2];
82 static uint8 KTAOF[2];
83 
84 static struct
85 {
86  uint16 YStart, YEnd;
87  bool YEndMet;
88  bool YIn;
89 } Window[2];
90 
91 static uint16 VRAM[262144];
92 
93 static uint16 CRAM[2048];
94 
95 static struct
96 {
97  // Signed values are stored sign-extended to the full 32 bits.
98  int32 Xst, Yst, Zst;	// 1.12.10
99  int32 DXst, DYst;	// 1. 2.10
100  int32 DX, DY;		// 1. 2.10
101  int32 RotMatrix[6];	// 1. 3.10
102  int32 Px, Py, Pz;	// 1.13. 0
103  int32 Cx, Cy, Cz;	// 1.13. 0
104  int32 Mx, My;		// 1.13.10
105  int32 kx, ky;		// 1. 7.16
106 
107  uint32 KAst;		// 0.16.10
108  uint32 DKAst;		// 1. 9.10
109  uint32 DKAx;		// 1. 9.10
110  //
111  //
112  //
113  uint32 XstAccum, YstAccum;	// 1.12.10 (sorta)
114  uint32 KAstAccum;		//     .10
115 } RotParams[2];
116 
FetchRotParams(const bool field)117 static void FetchRotParams(const bool field)
118 {
119  uint32 a = RPTA & 0x7FFBE;
120 
121  for(unsigned i = 0; i < 2; i++)
122  {
123   auto& rp = RotParams[i];
124 
125   rp.Xst = sign_x_to_s32(23, ne16_rbo_be<uint32>(VRAM, ((a + 0x00) & 0x3FFFF) << 1) >> 6);
126   rp.Yst = sign_x_to_s32(23, ne16_rbo_be<uint32>(VRAM, ((a + 0x02) & 0x3FFFF) << 1) >> 6);
127   rp.Zst = sign_x_to_s32(23, ne16_rbo_be<uint32>(VRAM, ((a + 0x04) & 0x3FFFF) << 1) >> 6);
128 
129   rp.DXst = sign_x_to_s32(13, ne16_rbo_be<uint32>(VRAM, ((a + 0x06) & 0x3FFFF) << 1) >> 6);
130   rp.DYst = sign_x_to_s32(13, ne16_rbo_be<uint32>(VRAM, ((a + 0x08) & 0x3FFFF) << 1) >> 6);
131 
132   rp.DX = sign_x_to_s32(13, ne16_rbo_be<uint32>(VRAM, ((a + 0x0A) & 0x3FFFF) << 1) >> 6);
133   rp.DY = sign_x_to_s32(13, ne16_rbo_be<uint32>(VRAM, ((a + 0x0C) & 0x3FFFF) << 1) >> 6);
134 
135   for(unsigned m = 0; m < 6; m++)
136   {
137    rp.RotMatrix[m] = sign_x_to_s32(14, ne16_rbo_be<uint32>(VRAM, ((a + 0x0E + (m << 1)) & 0x3FFFF) << 1) >> 6);
138   }
139 
140   rp.Px = sign_x_to_s32(14, VRAM[(a + 0x1A) & 0x3FFFF]);
141   rp.Py = sign_x_to_s32(14, VRAM[(a + 0x1B) & 0x3FFFF]);
142   rp.Pz = sign_x_to_s32(14, VRAM[(a + 0x1C) & 0x3FFFF]);
143 
144   rp.Cx = sign_x_to_s32(14, VRAM[(a + 0x1E) & 0x3FFFF]);
145   rp.Cy = sign_x_to_s32(14, VRAM[(a + 0x1F) & 0x3FFFF]);
146   rp.Cz = sign_x_to_s32(14, VRAM[(a + 0x20) & 0x3FFFF]);
147 
148   rp.Mx = sign_x_to_s32(24, ne16_rbo_be<uint32>(VRAM, ((a + 0x22) & 0x3FFFF) << 1) >> 6);
149   rp.My = sign_x_to_s32(24, ne16_rbo_be<uint32>(VRAM, ((a + 0x24) & 0x3FFFF) << 1) >> 6);
150 
151   rp.kx = sign_x_to_s32(24, ne16_rbo_be<uint32>(VRAM, ((a + 0x26) & 0x3FFFF) << 1));
152   rp.ky = sign_x_to_s32(24, ne16_rbo_be<uint32>(VRAM, ((a + 0x28) & 0x3FFFF) << 1));
153 
154   rp.KAst = ne16_rbo_be<uint32>(VRAM, ((a + 0x2A) & 0x3FFFF) << 1) >> 6;
155   rp.DKAst = sign_x_to_s32(20, ne16_rbo_be<uint32>(VRAM, ((a + 0x2C) & 0x3FFFF) << 1) >> 6);
156   rp.DKAx = sign_x_to_s32(20, ne16_rbo_be<uint32>(VRAM, ((a + 0x2E) & 0x3FFFF) << 1) >> 6);
157 
158   a += 0x40;
159   //
160   // Interlace mode doesn't seem to affect operation?
161   //
162   // const bool imft = (InterlaceMode == IM_DOUBLE && field);
163 
164   if(RPRCTL[i] & 0x01)
165    rp.XstAccum = rp.Xst; // + rp.DXst * imft;
166   else
167    rp.XstAccum += rp.DXst; // << (InterlaceMode == IM_DOUBLE);
168 
169   if(RPRCTL[i] & 0x02)
170    rp.YstAccum = rp.Yst; // + rp.DYst * imft;
171   else
172    rp.YstAccum += rp.DYst; // << (InterlaceMode == IM_DOUBLE);
173 
174   if(RPRCTL[i] & 0x04)
175    rp.KAstAccum = (KTAOF[i] << 26) + rp.KAst; // + rp.DKAst * imft;
176   else
177    rp.KAstAccum += rp.DKAst; // << (InterlaceMode == IM_DOUBLE);
178  }
179 }
180 
181 enum
182 {
183  VPHASE_ACTIVE = 0,
184 
185  VPHASE_BOTTOM_BORDER,
186  VPHASE_BOTTOM_BLANKING,
187 
188  VPHASE_VSYNC,
189 
190  VPHASE_TOP_BLANKING,
191  VPHASE_TOP_BORDER,
192 
193  VPHASE__COUNT
194 };
195 
196 static const int32 VTimings[2][4][VPHASE__COUNT] = // End lines
197 {
198  { // NTSC:
199   { 0x0E0, 0xE8, 0xED, 0xF0, 0x0FF, 0x107 },
200   { 0x0F0, 0xF0, 0xF5, 0xF8, 0x107, 0x107 },
201   { 0x0E0, 0xE8, 0xED, 0xF0, 0x0FF, 0x107 },
202   { 0x0F0, 0xF0, 0xF5, 0xF8, 0x107, 0x107 },
203  },
204  { // PAL:
205   // btm brdr begin, btm blnk begin, vsync begin, /***/ top blnk begin, top brdr begin, total
206   { 0x0E0, 0x100, 0x103, /***/ 0x103 + 3/*?*/, 0x119, 0x139 },
207   { 0x0F0, 0x108, 0x10B, /***/ 0x10B + 3/*?*/, 0x121, 0x139 },
208   { 0x100, 0x110, 0x113, /***/ 0x113 + 3/*?*/, 0x129, 0x139 },
209   { 0x100, 0x110, 0x113, /***/ 0x113 + 3/*?*/, 0x129, 0x139 },
210  },
211 };
212 
213 static bool Out_VB;	// VB output signal
214 
215 static uint32 VPhase;
216 /*static*/ int32 VCounter;
217 static bool InternalVB;
218 static bool Odd;
219 
220 static uint32 CRTLineCounter;
221 static bool Clock28M;
222 //
223 static int SurfInterlaceField;
224 //
225 //
226 //
227 
228 
229 //  (No 0)  8 accesses, No split: 0 added cycles
230 //  (No 4)  4 accesses, No split: 1 added cycles
231 //  (No 6)  2 accesses, No split: 2 added cycles
232 //  (No 7)  1 accesses, No split: 3, Split: 3.51? added cycles
233 //  (No 8)  0 accesses, No split: 4, Split: 5.34? added cycles
RecalcVRAMPenalty(void)234 static INLINE void RecalcVRAMPenalty(void)
235 {
236  if(InternalVB)
237   VRAMPenalty[0] = VRAMPenalty[1] = VRAMPenalty[2] = VRAMPenalty[3] = 0;
238  else
239  {
240   const unsigned VRAM_Mode = (RAMCTL_Raw >> 8) & 0x3;
241   const unsigned RDBS_Mode = (RAMCTL_Raw & 0xFF);
242   const size_t sh = ((HRes & 0x6) ? 0 : 4);
243   uint8 vcp_type_penalty[0x10];
244 
245   for(unsigned vcp_type = 0; vcp_type < 0x10; vcp_type++)
246   {
247    bool penalty;
248 
249    if((vcp_type < 0x8) || vcp_type == 0xC || vcp_type == 0xD)
250     penalty = (bool)(BGON & (1U << (vcp_type & 0x3)));
251    else
252     penalty = false;
253 
254    vcp_type_penalty[vcp_type] = penalty;
255   }
256 
257   for(unsigned bank = 0; bank < 4; bank++)
258   {
259    const unsigned esb = bank & (2 | ((VRAM_Mode >> (bank >> 1)) & 1));
260    const uint8 rdbs = (RDBS_Mode >> (esb << 1)) & 0x3;
261    uint32 tmp = 0;
262 
263    if(BGON & 0x20)
264    {
265     if(bank >= 2 || ((BGON & 0x10) && rdbs != RDBS_UNUSED))
266      tmp = 8;
267    }
268    else
269    {
270     if((BGON & 0x10) && rdbs != RDBS_UNUSED)
271      tmp = 8;
272     else if(BGON & 0x0F)
273     {
274      tmp += vcp_type_penalty[VCPRegs[esb][0]];
275      tmp += vcp_type_penalty[VCPRegs[esb][1]];
276      tmp += vcp_type_penalty[VCPRegs[esb][2]];
277      tmp += vcp_type_penalty[VCPRegs[esb][3]];
278 
279      tmp += vcp_type_penalty[VCPRegs[esb][sh + 0]];
280      tmp += vcp_type_penalty[VCPRegs[esb][sh + 1]];
281      tmp += vcp_type_penalty[VCPRegs[esb][sh + 2]];
282      tmp += vcp_type_penalty[VCPRegs[esb][sh + 3]];
283     }
284    }
285 
286    static const uint8 tab[9] = { 0, 0, 0, 0, 1, 1, 2, 3, 4 };
287    VRAMPenalty[bank] = tab[tmp];
288    //printf("%d, %d\n", bank, tmp);
289   }
290  }
291 }
292 
293 enum
294 {
295  HPHASE_ACTIVE = 0,
296 
297  HPHASE_RIGHT_BORDER,
298  HPHASE_HSYNC,
299 
300  // ... ? ? ?
301 
302  HPHASE__COUNT
303 };
304 
305 static const int32 HTimings[2][HPHASE__COUNT] =
306 {
307  { 0x140, 0x15B, 0x1AB },
308  { 0x160, 0x177, 0x1C7 },
309 };
310 
311 static uint32 HPhase;
312 /*static*/ int32 HCounter;
313 
314 static uint16 Latched_VCNT, Latched_HCNT;
315 static bool HVIsExLatched;
316 bool ExLatchIn;
317 bool ExLatchPending;
318 
319 
GetNLVCounter(void)320 static INLINE unsigned GetNLVCounter(void)
321 {
322  unsigned ret;
323 
324  if(VPhase >= VPHASE_VSYNC)
325   ret = VCounter + (0x200 - VTimings[PAL][VRes][VPHASE__COUNT - 1]);
326  else
327   ret = VCounter;
328 
329  if(InterlaceMode == IM_DOUBLE)
330   ret = (ret << 1) | !Odd;
331 
332  return ret;
333 }
334 
LatchHV(void)335 static void LatchHV(void)
336 {
337  Latched_VCNT = GetNLVCounter();
338 
339  if(HPhase >= HPHASE_HSYNC)
340   Latched_HCNT = (HCounter + (0x200 - HTimings[HRes & 1][HPHASE__COUNT - 1])) << 1;
341  else
342   Latched_HCNT = HCounter << 1;
343 }
344 
345 //
346 //
GetGunXTranslation(const bool clock28m,float * scale,float * offs)347 void GetGunXTranslation(const bool clock28m, float* scale, float* offs)
348 {
349  VDP2REND_GetGunXTranslation(clock28m, scale, offs);
350 }
351 
StartFrame(EmulateSpecStruct * espec,const bool clock28m)352 void StartFrame(EmulateSpecStruct* espec, const bool clock28m)
353 {
354  Clock28M = clock28m;
355  //printf("StartFrame: %d\n", SurfInterlaceField);
356  VDP2REND_StartFrame(espec, clock28m, SurfInterlaceField);
357  CRTLineCounter = 0;
358 }
359 
360 //
361 //
IncVCounter(const sscpu_timestamp_t event_timestamp)362 static INLINE void IncVCounter(const sscpu_timestamp_t event_timestamp)
363 {
364  const unsigned prev_nlvc = GetNLVCounter();
365  //
366  VCounter = (VCounter + 1) & 0x1FF;
367 
368  if(VCounter == (VTimings[PAL][VRes][VPHASE__COUNT - 1] - 1))
369  {
370   Out_VB = false;
371   Window[0].YEndMet = Window[1].YEndMet = false;
372  }
373 
374 #if 1
375  if(MDFN_UNLIKELY(ss_horrible_hacks & HORRIBLEHACK_NOSH2DMALINE106))
376  {
377   const bool s = (VCounter == (VTimings[PAL][VRes][VPHASE__COUNT - 1] - 1));
378 
379   for(size_t i = 0; i < 2; i++)
380    CPU[i].SetExtHaltDMAKludgeFromVDP2(s);
381  }
382 #endif
383 
384  // - 1, so the CPU loop will  have plenty of time to exit before we reach non-hblank top border area
385  // (exit granularity could be large if program is executing from SCSP RAM space, for example).
386  if(VCounter == (VTimings[PAL][VRes][VPHASE_TOP_BLANKING] - 1))
387  {
388 #if 0
389   for(unsigned bank = 0; bank < 4; bank++)
390   {
391    printf("Bank %d: ", bank);
392    for(unsigned vc = 0; vc < 8; vc++)
393     printf("%01x ", VCPRegs[bank][vc]);
394    printf("\n");
395   }
396 #endif
397 
398   SS_RequestMLExit();
399   VDP2REND_EndFrame();
400   //printf("Meow: %d\n", VCounter);
401  }
402 
403  while(VCounter >= VTimings[PAL][VRes][VPhase] - ((VPhase == VPHASE_VSYNC - 1) && InterlaceMode))
404  {
405   VPhase++;
406 
407   if(VPhase == VPHASE__COUNT)
408   {
409    VPhase = 0;
410    VCounter -= VTimings[PAL][VRes][VPHASE__COUNT - 1];
411   }
412 
413   if(VPhase == VPHASE_ACTIVE)
414    InternalVB = !DisplayOn;
415   else if(VPhase == VPHASE_BOTTOM_BORDER)
416   {
417    SS_SetEventNT(&events[SS_EVENT_MIDSYNC], event_timestamp + 1);
418    InternalVB = true;
419    Out_VB = true;
420   }
421   else if(VPhase == VPHASE_BOTTOM_BLANKING)
422   {
423    CRTLineCounter = 0x80000000U;
424   }
425   else if(VPhase == VPHASE_VSYNC)
426   {
427    if(InterlaceMode)
428    {
429     Odd = !Odd;
430     VCounter += Odd;
431     SurfInterlaceField = !Odd;
432    }
433    else
434    {
435     SurfInterlaceField = -1;
436     Odd = true;
437    }
438   }
439  }
440 
441  //
442  //
443  {
444   const unsigned nlvc = GetNLVCounter();
445   const unsigned mask = (InterlaceMode == IM_DOUBLE) ? 0x1FE : 0x1FF;
446 
447   for(unsigned d = 0; d < 2; d++)
448   {
449    if((nlvc & mask) == (Window[d].YStart & mask))
450    {
451     //printf("Window%d YStartMet at VC=0x%03x ---- %03x %03x\n", d, nlvc, Window[d].YStart, Window[d].YEnd);
452     Window[d].YIn = true;
453    }
454 
455    if((prev_nlvc & mask) == (Window[d].YEnd & mask))
456    {
457     //printf("Window%d YEndMet at VC=0x%03x ---- %03x %03x\n", d, nlvc, Window[d].YStart, Window[d].YEnd);
458     Window[d].YEndMet = true;
459    }
460 
461    Window[d].YIn &= !Window[d].YEndMet;
462   }
463  }
464  //
465  //
466 
467  RecalcVRAMPenalty();
468 
469  SMPC_SetVBVS(event_timestamp, Out_VB, VPhase == VPHASE_VSYNC);
470 }
471 
AddHCounter(const sscpu_timestamp_t event_timestamp,int32 count)472 static INLINE int32 AddHCounter(const sscpu_timestamp_t event_timestamp, int32 count)
473 {
474  HCounter += count;
475 
476  //if(HCounter > HTimings[HRes & 1][HPhase])
477  // printf("VDP2 oops: %d %d\n", HCounter, HTimings[HRes & 1][HPhase]);
478 
479  while(HCounter >= HTimings[HRes & 1][HPhase])
480  {
481   HPhase++;
482 
483   if(HPhase == HPHASE__COUNT)
484   {
485    HPhase = 0;
486    HCounter -= HTimings[HRes & 1][HPHASE__COUNT - 1];
487   }
488   //
489   //
490   //
491   if(HPhase == HPHASE_ACTIVE)
492   {
493    {
494     const int32 div = Clock28M ? 61 : 65;
495     const int32 coord_adj = 6832 - 80 * div;
496 
497     SMPC_LineHook(event_timestamp, CRTLineCounter, div, coord_adj);
498    }
499 
500    if(VPhase == VPHASE_ACTIVE)
501    {
502     VDP2Rend_LIB* lib = VDP2REND_GetLIB(VCounter);
503 
504     lib->win_ymet[0] = Window[0].YIn;
505     lib->win_ymet[1] = Window[1].YIn;
506 
507     if(!InternalVB)
508     {
509      if(BGON & 0x30)
510      {
511       if(VCounter == 0)
512        RPRCTL[0] = RPRCTL[1] = 0x07;
513       FetchRotParams(false/*field*/);
514       RPRCTL[0] = RPRCTL[1] = 0;
515      }
516 
517      for(unsigned i = 0; i < 2; i++)
518      {
519       auto const& rp = RotParams[i];
520       auto& r = lib->rv[i];
521 
522       r.Xsp = ((int64)rp.RotMatrix[0] * ((int32)rp.XstAccum - (rp.Px * 1024)) +
523 	      (int64)rp.RotMatrix[1] * ((int32)rp.YstAccum - (rp.Py * 1024)) +
524 	      (int64)rp.RotMatrix[2] * (rp.Zst      - (rp.Pz * 1024))) >> 10;
525       r.Ysp = ((int64)rp.RotMatrix[3] * ((int32)rp.XstAccum - (rp.Px * 1024)) +
526 	      (int64)rp.RotMatrix[4] * ((int32)rp.YstAccum - (rp.Py * 1024)) +
527 	      (int64)rp.RotMatrix[5] * (rp.Zst      - (rp.Pz * 1024))) >> 10;
528 
529       r.Xp = rp.RotMatrix[0] * (rp.Px - rp.Cx) +
530 	    rp.RotMatrix[1] * (rp.Py - rp.Cy) +
531 	    rp.RotMatrix[2] * (rp.Pz - rp.Cz) +
532 	    (rp.Cx * 1024) + rp.Mx;
533 
534       r.Yp = rp.RotMatrix[3] * (rp.Px - rp.Cx) +
535 	    rp.RotMatrix[4] * (rp.Py - rp.Cy) +
536 	    rp.RotMatrix[5] * (rp.Pz - rp.Cz) +
537 	    (rp.Cy * 1024) + rp.My;
538 
539       r.dX = (rp.RotMatrix[0] * rp.DX + rp.RotMatrix[1] * rp.DY) >> 10;
540       r.dY = (rp.RotMatrix[3] * rp.DX + rp.RotMatrix[4] * rp.DY) >> 10;
541 
542       r.kx = rp.kx;
543       r.ky = rp.ky;
544 
545       r.KAstAccum = rp.KAstAccum;
546       r.DKAx = rp.DKAx;
547      }
548     }
549     //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);
550     //printf("DL: %d\n", VCounter);
551     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.
552     VDP2REND_DrawLine(InternalVB ? -1 : VCounter, CRTLineCounter, !Odd);
553     CRTLineCounter++;
554    }
555    else if(VPhase == VPHASE_TOP_BORDER || VPhase == VPHASE_BOTTOM_BORDER)
556    {
557     VDP2REND_DrawLine(-1, CRTLineCounter, !Odd);
558     CRTLineCounter++;
559    }
560   }
561   else if(HPhase == HPHASE_HSYNC)
562   {
563    IncVCounter(event_timestamp);
564   }
565  }
566 
567  return (HTimings[HRes & 1][HPhase] - HCounter);
568 }
569 
Update(sscpu_timestamp_t timestamp)570 sscpu_timestamp_t Update(sscpu_timestamp_t timestamp)
571 {
572  int32 clocks = (timestamp - lastts) >> 2;
573 
574  if(MDFN_UNLIKELY(timestamp < lastts))
575  {
576   SS_DBGTI(SS_DBG_WARNING | SS_DBG_VDP2, "[VDP2] [BUG] timestamp(%d) < lastts(%d)", timestamp, lastts);
577   clocks = 0;
578  }
579 
580  lastts += clocks << 2;
581  //
582  //
583  int32 ne;
584  int32 tmp;
585 
586  ne = AddHCounter(timestamp, clocks);
587  VDP1::SetHBVB(timestamp, HPhase > HPHASE_ACTIVE, Out_VB);
588  tmp = SCU_SetHBVB(clocks, HPhase > HPHASE_ACTIVE, Out_VB);
589  if(tmp < ne)
590   ne = tmp;
591 
592  //
593  //
594  //
595  if(MDFN_UNLIKELY(ExLatchPending))
596  {
597   LatchHV();
598   HVIsExLatched = true;
599   ExLatchPending = false;
600   //printf("ExLatch: %04x %04x\n", Latched_VCNT, Latched_HCNT);
601  }
602 
603  return lastts + (ne << 2);
604 }
605 
606 //
607 // Register writes seem to always be 16-bit
608 //
RegsWrite(uint32 A,uint16 V)609 static INLINE void RegsWrite(uint32 A, uint16 V)
610 {
611  A &= 0x1FE;
612 
613  RawRegs[A >> 1] = V;
614 
615  SS_DBGTI(SS_DBG_VDP2_REGW, "[VDP2] Register write 0x%03x: 0x%04x", A, V);
616 
617  switch(A)
618  {
619   default:
620 //	SS_DBGTI(SS_DBG_WARNING | SS_DBG_VDP2, "[VDP2] Unknown write to register at 0x%08x of value 0x%04x", A, V);
621 	break;
622 
623   case 0x00:
624 	Update(SH7095_mem_timestamp);
625 	//
626 	DisplayOn = (V >> 15) & 0x1;
627 	BorderMode = (V >> 8) & 0x1;
628 	InterlaceMode = (V >> 6) & 0x3;
629 	VRes = (V >> 4) & 0x3;
630 	HRes = (V >> 0) & 0x7;
631 	//
632 	InternalVB |= !DisplayOn;
633 	//
634 	SS_SetEventNT(&events[SS_EVENT_VDP2], Update(SH7095_mem_timestamp));
635 	break;
636 
637   case 0x02:
638 	ExLatchEnable = (V >> 9) & 0x1;
639 	ExSyncEnable = (V >> 8) & 0x1;
640 
641 	DispAreaSelect = (V >> 1) & 0x1;
642 	ExBGEnable = (V >> 0) & 0x1;
643 	break;
644 
645   case 0x06:
646 	VRAMSize = (V >> 15) & 0x1;
647 
648 	if(VRAMSize)
649 	 SS_DBGTI(SS_DBG_WARNING | SS_DBG_VDP2, "[VDP2] VRAMSize=%d (unemulated)", VRAMSize);
650 	break;
651 
652   case 0x0E:
653 	RAMCTL_Raw = V & 0xB3FF;
654 	CRAM_Mode = (V >> 12) & 0x3;
655 	break;
656 
657   case 0x10:
658   case 0x12:
659   case 0x14:
660   case 0x16:
661   case 0x18:
662   case 0x1A:
663   case 0x1C:
664   case 0x1E:
665 	{
666 	 uint8* const b = &VCPRegs[(A >> 2) & 3][(A & 0x2) << 1];
667 	 b[0] = (V >> 12) & 0xF;
668 	 b[1] = (V >>  8) & 0xF;
669 	 b[2] = (V >>  4) & 0xF;
670 	 b[3] = (V >>  0) & 0xF;
671 	}
672 	break;
673 
674   case 0x20:
675 	BGON = V & 0x1F3F;
676 	break;
677 
678   case 0xB2:
679 	RPRCTL[0] = (V >> 0) & 0x7;
680 	RPRCTL[1] = (V >> 8) & 0x7;
681 	break;
682 
683   case 0xB6:
684 	KTAOF[0] = (V >> 0) & 0x7;
685 	KTAOF[1] = (V >> 8) & 0x7;
686 	break;
687 
688   case 0xBC:
689 	RPTA = (RPTA & 0xFFFF) | ((V & 0x7) << 16);
690 	break;
691 
692   case 0xBE:
693 	RPTA = (RPTA & ~0xFFFF) | (V & 0xFFFE);
694 	break;
695 
696   case 0xC2: Window[0].YStart = V & 0x1FF; break;
697   case 0xC6: Window[0].YEnd = V & 0x1FF; break;
698 
699   case 0xCA: Window[1].YStart = V & 0x1FF; break;
700   case 0xCE: Window[1].YEnd = V & 0x1FF; break;
701  }
702 }
703 
RegsRead(uint32 A)704 static INLINE uint16 RegsRead(uint32 A)
705 {
706  switch(A & 0x1FE)
707  {
708   default:
709 	SS_DBGTI(SS_DBG_WARNING | SS_DBG_VDP2, "[VDP2] Unknown read from 0x%08x", A);
710 	return 0;
711 
712   case 0x00:
713 	return (DisplayOn << 15) | (BorderMode << 8) | (InterlaceMode << 6) | (VRes << 4) | (HRes << 0);
714 
715   case 0x02:
716 	if(!ExLatchEnable)
717 	{
718 	 SS_SetEventNT(&events[SS_EVENT_VDP2], Update(SH7095_mem_timestamp));
719  	 LatchHV();
720 	}
721 	return (ExLatchEnable << 9) | (ExSyncEnable << 8) | (DispAreaSelect << 1) | (ExBGEnable << 0);
722 
723   case 0x04:
724 	SS_SetEventNT(&events[SS_EVENT_VDP2], Update(SH7095_mem_timestamp));
725 	{
726 	 // TODO: EXSYFG
727 	 uint16 ret = (HVIsExLatched << 9) | (InternalVB << 3) | ((HPhase > HPHASE_ACTIVE) << 2) | (Odd << 1) | (PAL << 0);
728 
729 	 HVIsExLatched = false;
730 
731 	 return ret;
732 	}
733 
734   case 0x06:
735 	return VRAMSize << 15;
736 
737   case 0x08:
738 	return Latched_HCNT;
739 
740   case 0x0A:
741 	return Latched_VCNT;
742 
743   case 0x0E:
744 	return RAMCTL_Raw;
745  }
746 }
747 
748 template<typename T, bool IsWrite>
RW(uint32 A,uint16 * DB)749 static INLINE uint32 RW(uint32 A, uint16* DB)
750 {
751  static_assert(IsWrite || sizeof(T) == 2, "Wrong type for read.");
752 
753  A &= 0x1FFFFF;
754 
755  //
756  // VRAM
757  //
758  if(A < 0x100000)
759  {
760   const size_t vri = (A & 0x7FFFF) >> 1;
761 
762   if(IsWrite)
763   {
764    const unsigned mask = (sizeof(T) == 2) ? 0xFFFF : (0xFF00 >> ((A & 1) << 3));
765 
766    VRAM[vri] = (VRAM[vri] &~ mask) | (*DB & mask);
767   }
768   else
769    *DB = VRAM[vri];
770 
771   return VRAMPenalty[vri >> 16];
772  }
773 
774  //
775  // CRAM
776  //
777  if(A < 0x180000)
778  {
779   const unsigned cri = (A & 0xFFF) >> 1;
780 
781   if(IsWrite)
782   {
783    switch(CRAM_Mode)
784    {
785     case CRAM_MODE_RGB555_1024:
786 	(CRAM + 0x000)[cri & 0x3FF] = *DB;
787 	(CRAM + 0x400)[cri & 0x3FF] = *DB;
788 	break;
789 
790     case CRAM_MODE_RGB555_2048:
791 	CRAM[cri] = *DB;
792 	break;
793 
794     case CRAM_MODE_RGB888_1024:
795     case CRAM_MODE_ILLEGAL:
796     default:
797 	CRAM[((cri >> 1) & 0x3FF) | ((cri & 1) << 10)] = *DB;
798 	break;
799    }
800   }
801   else
802   {
803    switch(CRAM_Mode)
804    {
805     case CRAM_MODE_RGB555_1024:
806     case CRAM_MODE_RGB555_2048:
807 	*DB = CRAM[cri];
808 	break;
809 
810     case CRAM_MODE_RGB888_1024:
811     case CRAM_MODE_ILLEGAL:
812     default:
813 	*DB = CRAM[((cri >> 1) & 0x3FF) | ((cri & 1) << 10)];
814 	break;
815    }
816   }
817 
818   return 0;
819  }
820 
821  //
822  // Registers
823  //
824  if(A < 0x1C0000)
825  {
826   if(IsWrite)
827   {
828    if(sizeof(T) == 1)
829     SS_DBGTI(SS_DBG_WARNING | SS_DBG_VDP2, "[VDP2] Byte-write to register at 0x%08x(DB=0x%04x)", A, *DB);
830 
831    RegsWrite(A, *DB);
832   }
833   else
834    *DB = RegsRead(A);
835 
836   return 0;
837  }
838 
839  if(IsWrite)
840  {
841   //SS_DBGTI(SS_DBG_WARNING | SS_DBG_VDP2, "[VDP2] Unknown %zu-byte write to 0x%08x(DB=0x%04x)", sizeof(T), A, *DB);
842  }
843  else
844  {
845   //SS_DBGTI(SS_DBG_WARNING | SS_DBG_VDP2, "[VDP2] Unknown %zu-byte read from 0x%08x", sizeof(T), A);
846   *DB = 0;
847  }
848 
849  return 0;
850 }
851 
Read16_DB(uint32 A)852 uint16 Read16_DB(uint32 A)
853 {
854  uint16 DB;
855 
856  RW<uint16, false>(A, &DB);
857 
858  return DB;
859 }
860 
861 
Write8_DB(uint32 A,uint16 DB)862 uint32 Write8_DB(uint32 A, uint16 DB)
863 {
864  VDP2REND_Write8_DB(A, DB);
865 
866  return RW<uint8, true>(A, &DB);
867 }
868 
Write16_DB(uint32 A,uint16 DB)869 uint32 Write16_DB(uint32 A, uint16 DB)
870 {
871  VDP2REND_Write16_DB(A, DB);
872 
873  return RW<uint16, true>(A, &DB);
874 }
875 
876 
877 //
878 //
879 //
880 
AdjustTS(const int32 delta)881 void AdjustTS(const int32 delta)
882 {
883  lastts += delta;
884 }
885 
886 
Init(const bool IsPAL,const uint64 affinity)887 void Init(const bool IsPAL, const uint64 affinity)
888 {
889  SurfInterlaceField = -1;
890  PAL = IsPAL;
891  lastts = 0;
892  CRTLineCounter = 0x80000000U;
893  Clock28M = false;
894 
895  SS_SetPhysMemMap(0x05E00000, 0x05EFFFFF, VRAM, 0x80000, true);
896 
897  ExLatchIn = false;
898 
899  VDP2REND_Init(IsPAL, affinity);
900 }
901 
SetGetVideoParams(MDFNGI * gi,const bool caspect,const int sls,const int sle,const bool show_h_overscan,const bool dohblend)902 void SetGetVideoParams(MDFNGI* gi, const bool caspect, const int sls, const int sle, const bool show_h_overscan, const bool dohblend)
903 {
904  if(PAL)
905   gi->fps = 65536 * 256 * (1734687500.0 / 61 / 4 / 455 / ((313 + 312.5) / 2.0));
906  else
907   gi->fps = 65536 * 256 * (1746818181.8 / 61 / 4 / 455 / ((263 + 262.5) / 2.0));
908 
909  VDP2REND_SetGetVideoParams(gi, caspect, sls, sle, show_h_overscan, dohblend);
910 }
911 
Kill(void)912 void Kill(void)
913 {
914  VDP2REND_Kill();
915 }
916 
917 //
918 // TODO: Check reset versus power on values.
919 //
Reset(bool powering_up)920 void Reset(bool powering_up)
921 {
922  memset(RawRegs, 0, sizeof(RawRegs));
923 
924  DisplayOn = false;
925  BorderMode = false;
926  ExLatchEnable = false;
927  ExSyncEnable = false;
928  ExBGEnable = false;
929  DispAreaSelect = false;
930  HRes = 0;
931  VRes = 0;
932  InterlaceMode = 0;
933 
934  VRAMSize = 0;
935 
936  InternalVB = true;
937  Out_VB = false;
938  VPhase = VPHASE_ACTIVE;
939  VCounter = 0;
940  Odd = true;
941 
942  for(size_t i = 0; i < 2; i++)
943   CPU[i].SetExtHaltDMAKludgeFromVDP2(false);
944 
945  RAMCTL_Raw = 0;
946  CRAM_Mode = 0;
947 
948  BGON = 0;
949 
950  memset(VCPRegs, 0, sizeof(VCPRegs));
951 
952  for(unsigned i = 0; i < 2; i++)
953  {
954   KTAOF[i] = 0;
955   RPRCTL[i] = 0;
956  }
957  RPTA = 0;
958  memset(RotParams, 0, sizeof(RotParams));
959 
960  for(unsigned w = 0; w < 2; w++)
961  {
962   Window[w].YStart = 0;
963   Window[w].YEnd = 0;
964   Window[w].YEndMet = false;
965   Window[w].YIn = false;
966  }
967  //
968  //
969  //
970  if(powering_up)
971  {
972   HPhase = 0;
973   HCounter = 0;
974 
975   Latched_VCNT = 0;
976   Latched_HCNT = 0;
977   HVIsExLatched = false;
978   ExLatchPending = false;
979  }
980  //
981  // FIXME(init values), also in VDP2REND.
982  if(powering_up)
983  {
984   memset(VRAM, 0, sizeof(VRAM));
985   memset(CRAM, 0, sizeof(CRAM));
986  }
987  //
988  RecalcVRAMPenalty();
989  //
990  //
991  VDP2REND_Reset(powering_up);
992 }
993 
994 //
995 //
996 //
997 //
GetRegister(const unsigned id,char * const special,const uint32 special_len)998 uint32 GetRegister(const unsigned id, char* const special, const uint32 special_len)
999 {
1000  uint32 ret = 0xDEADBEEF;
1001 
1002  switch(id)
1003  {
1004   case GSREG_LINE:
1005 	ret = VCounter;
1006 	break;
1007 
1008   case GSREG_DON:
1009 	ret = DisplayOn;
1010 	break;
1011 
1012   case GSREG_BM:
1013 	ret = BorderMode;
1014 	break;
1015 
1016   case GSREG_IM:
1017 	ret = InterlaceMode;
1018 	break;
1019 
1020   case GSREG_VRES:
1021 	ret = VRes;
1022 	break;
1023 
1024   case GSREG_HRES:
1025 	ret = HRes;
1026 	break;
1027 
1028   case GSREG_RAMCTL:
1029 	ret = RAMCTL_Raw;
1030 	break;
1031 
1032   case GSREG_CYCA0:
1033   case GSREG_CYCA1:
1034   case GSREG_CYCB0:
1035   case GSREG_CYCB1:
1036 	{
1037 	 static const char* tab[0x10] =
1038 	 {
1039 	  "NBG0 PN", "NBG1 PN", "NBG2 PN", "NBG3 PN",
1040 	  "NBG0 CG", "NBG1 CG", "NBG2 CG", "NBG3 CG",
1041 	  "ILLEGAL", "ILLEGAL", "ILLEGAL", "ILLEGAL",
1042 	  "NBG0 VCS", "NBG1 VCS", "CPU", "NOP"
1043 	 };
1044 	 const size_t idx = (id - GSREG_CYCA0);
1045 	 ret = (RawRegs[(0x10 >> 1) + (idx << 1)] << 16) | RawRegs[(0x12 >> 1) + (idx << 1)];
1046 
1047 	 if(special)
1048 	  trio_snprintf(special, special_len, "0: %s, 1: %s, 2: %s, 3: %s, 4: %s, 5: %s, 6: %s, 7: %s",
1049 		tab[(ret >> 28) & 0xF], tab[(ret >> 24) & 0xF], tab[(ret >> 20) & 0xF], tab[(ret >> 16) & 0xF],
1050 		tab[(ret >> 12) & 0xF], tab[(ret >>  8) & 0xF], tab[(ret >>  4) & 0xF], tab[(ret >>  0) & 0xF]);
1051 	}
1052 	break;
1053 
1054   case GSREG_BGON:
1055 	ret = BGON;
1056 	break;
1057 
1058   case GSREG_MZCTL:
1059 	ret = RawRegs[0x22 >> 1] & 0xFF1F;
1060 	break;
1061 
1062   case GSREG_SFSEL:
1063 	ret = RawRegs[0x24 >> 1] & 0x001F;
1064 	break;
1065 
1066   case GSREG_SFCODE:
1067 	ret = RawRegs[0x26 >> 1];
1068 	break;
1069 
1070   case GSREG_CHCTLA:
1071 	ret = RawRegs[0x28 >> 1] & 0x3F7F;
1072 	break;
1073 
1074   case GSREG_CHCTLB:
1075 	ret = RawRegs[0x2A >> 1] & 0x7733;
1076 	break;
1077   //
1078   //
1079   case GSREG_SCXIN0:
1080 	ret = RawRegs[0x70 >> 1] & 0x07FF;
1081 	break;
1082 
1083   case GSREG_SCXDN0:
1084 	ret = RawRegs[0x72 >> 1] & 0xFF00;
1085 	break;
1086 
1087   case GSREG_SCYIN0:
1088 	ret = RawRegs[0x74 >> 1] & 0x07FF;
1089 	break;
1090 
1091   case GSREG_SCYDN0:
1092 	ret = RawRegs[0x76 >> 1] & 0xFF00;
1093 	break;
1094 
1095   case GSREG_ZMXIN0:
1096 	ret = RawRegs[0x78 >> 1] & 0x0007;
1097 	break;
1098 
1099   case GSREG_ZMXDN0:
1100 	ret = RawRegs[0x7A >> 1] & 0xFF00;
1101 	break;
1102 
1103   case GSREG_ZMYIN0:
1104 	ret = RawRegs[0x7C >> 1] & 0x0007;
1105 	break;
1106 
1107   case GSREG_ZMYDN0:
1108 	ret = RawRegs[0x7E >> 1] & 0xFF00;
1109 	break;
1110 
1111   case GSREG_SCXIN1:
1112 	ret = RawRegs[0x80 >> 1] & 0x07FF;
1113 	break;
1114 
1115   case GSREG_SCXDN1:
1116 	ret = RawRegs[0x82 >> 1] & 0xFF00;
1117 	break;
1118 
1119   case GSREG_SCYIN1:
1120 	ret = RawRegs[0x84 >> 1] & 0x07FF;
1121 	break;
1122 
1123   case GSREG_SCYDN1:
1124 	ret = RawRegs[0x86 >> 1] & 0xFF00;
1125 	break;
1126 
1127   case GSREG_ZMXIN1:
1128 	ret = RawRegs[0x88 >> 1] & 0x0007;
1129 	break;
1130 
1131   case GSREG_ZMXDN1:
1132 	ret = RawRegs[0x8A >> 1] & 0xFF00;
1133 	break;
1134 
1135   case GSREG_ZMYIN1:
1136 	ret = RawRegs[0x8C >> 1] & 0x0007;
1137 	break;
1138 
1139   case GSREG_ZMYDN1:
1140 	ret = RawRegs[0x8E >> 1] & 0xFF00;
1141 	break;
1142 
1143   case GSREG_SCXN2:
1144 	ret = RawRegs[0x90 >> 1] & 0x07FF;
1145 	break;
1146 
1147   case GSREG_SCYN2:
1148 	ret = RawRegs[0x92 >> 1] & 0x07FF;
1149 	break;
1150 
1151   case GSREG_SCXN3:
1152 	ret = RawRegs[0x94 >> 1] & 0x07FF;
1153 	break;
1154 
1155   case GSREG_SCYN3:
1156 	ret = RawRegs[0x96 >> 1] & 0x07FF;
1157 	break;
1158 
1159   case GSREG_ZMCTL:
1160 	ret = RawRegs[0x98 >> 1] & 0x0303;
1161 	break;
1162 
1163   case GSREG_SCRCTL:
1164 	ret = RawRegs[0x9A >> 1] & 0x3F3F;
1165 	break;
1166  }
1167 
1168  return ret;
1169 }
1170 
SetRegister(const unsigned id,const uint32 value)1171 void SetRegister(const unsigned id, const uint32 value)
1172 {
1173  int rr = -1;
1174 
1175  switch(id)
1176  {
1177   case GSREG_BGON:
1178 	BGON = value & 0x1F3F;
1179 	rr = 0x20 >> 1;
1180 	break;
1181 
1182   case GSREG_MZCTL:
1183 	rr = 0x22 >> 1;
1184 	break;
1185 
1186   case GSREG_SFSEL:
1187 	rr = 0x24 >> 1;
1188 	break;
1189 
1190   case GSREG_SFCODE:
1191 	rr = 0x26 >> 1;
1192 	break;
1193 
1194   case GSREG_CHCTLA:
1195 	rr = 0x28 >> 1;
1196 	break;
1197 
1198   case GSREG_CHCTLB:
1199 	rr = 0x2A >> 1;
1200 	break;
1201   //
1202   //
1203   case GSREG_SCXIN0:
1204 	rr = 0x70 >> 1;
1205 	break;
1206 
1207   case GSREG_SCXDN0:
1208 	rr = 0x72 >> 1;
1209 	break;
1210 
1211   case GSREG_SCYIN0:
1212 	rr = 0x74 >> 1;
1213 	break;
1214 
1215   case GSREG_SCYDN0:
1216 	rr = 0x76 >> 1;
1217 	break;
1218 
1219   case GSREG_ZMXIN0:
1220 	rr = 0x78 >> 1;
1221 	break;
1222 
1223   case GSREG_ZMXDN0:
1224 	rr = 0x7A >> 1;
1225 	break;
1226 
1227   case GSREG_ZMYIN0:
1228 	rr = 0x7C >> 1;
1229 	break;
1230 
1231   case GSREG_ZMYDN0:
1232 	rr = 0x7E >> 1;
1233 	break;
1234 
1235   case GSREG_SCXIN1:
1236 	rr = 0x80 >> 1;
1237 	break;
1238 
1239   case GSREG_SCXDN1:
1240 	rr = 0x82 >> 1;
1241 	break;
1242 
1243   case GSREG_SCYIN1:
1244 	rr = 0x84 >> 1;
1245 	break;
1246 
1247   case GSREG_SCYDN1:
1248 	rr = 0x86 >> 1;
1249 	break;
1250 
1251   case GSREG_ZMXIN1:
1252 	rr = 0x88 >> 1;
1253 	break;
1254 
1255   case GSREG_ZMXDN1:
1256 	rr = 0x8A >> 1;
1257 	break;
1258 
1259   case GSREG_ZMYIN1:
1260 	rr = 0x8C >> 1;
1261 	break;
1262 
1263   case GSREG_ZMYDN1:
1264 	rr = 0x8E >> 1;
1265 	break;
1266 
1267   case GSREG_SCXN2:
1268 	rr = 0x90 >> 1;
1269 	break;
1270 
1271   case GSREG_SCYN2:
1272 	rr = 0x92 >> 1;
1273 	break;
1274 
1275   case GSREG_SCXN3:
1276 	rr = 0x94 >> 1;
1277 	break;
1278 
1279   case GSREG_SCYN3:
1280 	rr = 0x96 >> 1;
1281 	break;
1282 
1283   case GSREG_ZMCTL:
1284 	rr = 0x98 >> 1;
1285 	break;
1286 
1287   case GSREG_SCRCTL:
1288 	rr = 0x9A >> 1;
1289 	break;
1290  }
1291 
1292  if(rr >= 0)
1293  {
1294   RawRegs[rr] = (uint16)value;
1295   VDP2REND_Write16_DB(0x180000 + (rr << 1), RawRegs[rr]);
1296  }
1297 }
1298 
PeekVRAM(uint32 addr)1299 uint8 PeekVRAM(uint32 addr)
1300 {
1301  return ne16_rbo_be<uint8>(VRAM, addr & 0x7FFFF);
1302 }
1303 
PokeVRAM(uint32 addr,const uint8 val)1304 void PokeVRAM(uint32 addr, const uint8 val)
1305 {
1306  addr &= 0x7FFFF;
1307 
1308  ne16_wbo_be<uint8>(VRAM, addr, val);
1309  VDP2REND_Write16_DB(addr & ~1, ne16_rbo_be<uint16>(VRAM, addr & ~1));
1310 }
1311 
SetLayerEnableMask(uint64 mask)1312 void SetLayerEnableMask(uint64 mask)
1313 {
1314  VDP2REND_SetLayerEnableMask(mask);
1315 }
1316 
StateAction(StateMem * sm,const unsigned load,const bool data_only)1317 void StateAction(StateMem* sm, const unsigned load, const bool data_only)
1318 {
1319  SFORMAT StateRegs[] =
1320  {
1321   SFVAR(lastts),
1322 
1323   SFVAR(RawRegs),
1324   SFVAR(DisplayOn),
1325   SFVAR(BorderMode),
1326   SFVAR(ExLatchEnable),
1327   SFVAR(ExSyncEnable),
1328   SFVAR(ExBGEnable),
1329   SFVAR(DispAreaSelect),
1330 
1331   SFVAR(VRAMSize),
1332 
1333   SFVAR(HRes),
1334   SFVAR(VRes),
1335   SFVAR(InterlaceMode),
1336 
1337   SFVAR(RAMCTL_Raw),
1338   SFVAR(CRAM_Mode),
1339 
1340   SFVAR(BGON),
1341   SFVARN(VCPRegs, "&VCPRegs[0][0]"),
1342   SFVAR(VRAMPenalty),
1343 
1344   SFVAR(RPTA),
1345   SFVAR(RPRCTL),
1346   SFVAR(KTAOF),
1347 
1348   SFVAR(VRAM),
1349   SFVAR(CRAM),
1350 
1351   SFVAR(RotParams->Xst, 2, sizeof(*RotParams), RotParams),
1352   SFVAR(RotParams->Yst, 2, sizeof(*RotParams), RotParams),
1353   SFVAR(RotParams->Zst, 2, sizeof(*RotParams), RotParams),
1354   SFVAR(RotParams->DXst, 2, sizeof(*RotParams), RotParams),
1355   SFVAR(RotParams->DYst, 2, sizeof(*RotParams), RotParams),
1356   SFVAR(RotParams->DX, 2, sizeof(*RotParams), RotParams),
1357   SFVAR(RotParams->DY, 2, sizeof(*RotParams), RotParams),
1358   SFVAR(RotParams->RotMatrix, 2, sizeof(*RotParams), RotParams),
1359   SFVAR(RotParams->Px, 2, sizeof(*RotParams), RotParams),
1360   SFVAR(RotParams->Py, 2, sizeof(*RotParams), RotParams),
1361   SFVAR(RotParams->Pz, 2, sizeof(*RotParams), RotParams),
1362   SFVAR(RotParams->Cx, 2, sizeof(*RotParams), RotParams),
1363   SFVAR(RotParams->Cy, 2, sizeof(*RotParams), RotParams),
1364   SFVAR(RotParams->Cz, 2, sizeof(*RotParams), RotParams),
1365   SFVAR(RotParams->Mx, 2, sizeof(*RotParams), RotParams),
1366   SFVAR(RotParams->My, 2, sizeof(*RotParams), RotParams),
1367   SFVAR(RotParams->kx, 2, sizeof(*RotParams), RotParams),
1368   SFVAR(RotParams->ky, 2, sizeof(*RotParams), RotParams),
1369   SFVAR(RotParams->KAst, 2, sizeof(*RotParams), RotParams),
1370   SFVAR(RotParams->DKAst, 2, sizeof(*RotParams), RotParams),
1371   SFVAR(RotParams->DKAx, 2, sizeof(*RotParams), RotParams),
1372   SFVAR(RotParams->XstAccum, 2, sizeof(*RotParams), RotParams),
1373   SFVAR(RotParams->YstAccum, 2, sizeof(*RotParams), RotParams),
1374   SFVAR(RotParams->KAstAccum, 2, sizeof(*RotParams), RotParams),
1375 
1376   SFVAR(Out_VB),
1377 
1378   SFVAR(VPhase),
1379   SFVAR(VCounter),
1380   SFVAR(InternalVB),
1381   SFVAR(Odd),
1382 
1383   SFVAR(CRTLineCounter),
1384   SFVAR(Clock28M),
1385 //
1386   SFVAR(SurfInterlaceField),
1387 
1388   SFVAR(HPhase),
1389   SFVAR(HCounter),
1390 
1391   SFVAR(Latched_VCNT),
1392   SFVAR(Latched_HCNT),
1393   SFVAR(HVIsExLatched),
1394   SFVAR(ExLatchIn),
1395   SFVAR(ExLatchPending),
1396 
1397   SFVAR(Window->YStart, 2, sizeof(*Window), Window),
1398   SFVAR(Window->YEnd, 2, sizeof(*Window), Window),
1399   SFVAR(Window->YEndMet, 2, sizeof(*Window), Window),
1400   SFVAR(Window->YIn, 2, sizeof(*Window), Window),
1401 
1402   SFEND
1403  };
1404 
1405  MDFNSS_StateAction(sm, load, data_only, StateRegs, "VDP2");
1406 
1407  if(load)
1408  {
1409   if(load < 0x00102100)
1410   {
1411    Window[0].YStart = RawRegs[0xC2 >> 1] & 0x1FF;
1412    Window[0].YEnd = RawRegs[0xC6 >> 1] & 0x1FF;
1413 
1414    Window[1].YStart = RawRegs[0xCA >> 1] & 0x1FF;
1415    Window[1].YEnd = RawRegs[0xCE >> 1] & 0x1FF;
1416 
1417    //printf("%08x %03x:%03x, %03x:%03x\n", load, Window[0].YStart, Window[0].YEnd, Window[1].YStart, Window[1].YEnd);
1418 
1419    for(unsigned d = 0; d < 2; d++)
1420    {
1421     Window[d].YEndMet = false;
1422     Window[d].YIn = false;
1423    }
1424   }
1425  }
1426 
1427  VDP2REND_StateAction(sm, load, data_only, RawRegs, CRAM, VRAM);
1428 }
1429 
MakeDump(const std::string & path)1430 void MakeDump(const std::string& path)
1431 {
1432  FileStream fp(path, FileStream::MODE_WRITE);
1433 
1434  fp.print_format(" { ");
1435  for(unsigned i = 0; i < 0x100; i++)
1436   fp.print_format("0x%04x, ", RawRegs[i]);
1437  fp.print_format(" }, \n");
1438 
1439  fp.print_format(" { ");
1440  for(unsigned i = 0; i < 2048; i++)
1441   fp.print_format("0x%04x, ", CRAM[i]);
1442  fp.print_format(" }, \n");
1443 
1444  fp.print_format(" { ");
1445  for(unsigned i = 0; i < 0x40000; i++)
1446   fp.print_format("0x%04x, ", VRAM[i]);
1447  fp.print_format(" }, \n");
1448 
1449  fp.close();
1450 }
1451 
1452 }
1453 
1454 }
1455