1 /*  Copyright 2003-2005 Guillaume Duhamel
2     Copyright 2004-2007 Theo Berkau
3 
4     This file is part of Yabause.
5 
6     Yabause is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     Yabause is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with Yabause; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
19 */
20 
21 /*! \file vdp2.c
22     \brief VDP2 emulation functions
23 */
24 
25 #include <stdlib.h>
26 #include "vdp2.h"
27 #include "debug.h"
28 #include "peripheral.h"
29 #include "scu.h"
30 #include "sh2core.h"
31 #include "smpc.h"
32 #include "vdp1.h"
33 #include "yabause.h"
34 #include "movie.h"
35 #include "osdcore.h"
36 
37 u8 * Vdp2Ram;
38 u8 * Vdp2ColorRam;
39 Vdp2 * Vdp2Regs;
40 Vdp2Internal_struct Vdp2Internal;
41 Vdp2External_struct Vdp2External;
42 
43 struct CellScrollData cell_scroll_data[270];
44 Vdp2 Vdp2Lines[270];
45 
46 static int autoframeskipenab=0;
47 static int throttlespeed=0;
48 u64 lastticks=0;
49 static int fps;
50 int vdp2_is_odd_frame = 0;
51 
52 //////////////////////////////////////////////////////////////////////////////
53 
Vdp2RamReadByte(u32 addr)54 u8 FASTCALL Vdp2RamReadByte(u32 addr) {
55    addr &= 0x7FFFF;
56    return T1ReadByte(Vdp2Ram, addr);
57 }
58 
59 //////////////////////////////////////////////////////////////////////////////
60 
Vdp2RamReadWord(u32 addr)61 u16 FASTCALL Vdp2RamReadWord(u32 addr) {
62    addr &= 0x7FFFF;
63    return T1ReadWord(Vdp2Ram, addr);
64 }
65 
66 //////////////////////////////////////////////////////////////////////////////
67 
Vdp2RamReadLong(u32 addr)68 u32 FASTCALL Vdp2RamReadLong(u32 addr) {
69    addr &= 0x7FFFF;
70    return T1ReadLong(Vdp2Ram, addr);
71 }
72 
73 //////////////////////////////////////////////////////////////////////////////
74 
Vdp2RamWriteByte(u32 addr,u8 val)75 void FASTCALL Vdp2RamWriteByte(u32 addr, u8 val) {
76    addr &= 0x7FFFF;
77    T1WriteByte(Vdp2Ram, addr, val);
78 }
79 
80 //////////////////////////////////////////////////////////////////////////////
81 
Vdp2RamWriteWord(u32 addr,u16 val)82 void FASTCALL Vdp2RamWriteWord(u32 addr, u16 val) {
83    addr &= 0x7FFFF;
84    T1WriteWord(Vdp2Ram, addr, val);
85 }
86 
87 //////////////////////////////////////////////////////////////////////////////
88 
Vdp2RamWriteLong(u32 addr,u32 val)89 void FASTCALL Vdp2RamWriteLong(u32 addr, u32 val) {
90    addr &= 0x7FFFF;
91    T1WriteLong(Vdp2Ram, addr, val);
92 }
93 
94 //////////////////////////////////////////////////////////////////////////////
95 
Vdp2ColorRamReadByte(u32 addr)96 u8 FASTCALL Vdp2ColorRamReadByte(u32 addr) {
97    addr &= 0xFFF;
98    return T2ReadByte(Vdp2ColorRam, addr);
99 }
100 
101 //////////////////////////////////////////////////////////////////////////////
102 
Vdp2ColorRamReadWord(u32 addr)103 u16 FASTCALL Vdp2ColorRamReadWord(u32 addr) {
104    addr &= 0xFFF;
105    return T2ReadWord(Vdp2ColorRam, addr);
106 }
107 
108 //////////////////////////////////////////////////////////////////////////////
109 
Vdp2ColorRamReadLong(u32 addr)110 u32 FASTCALL Vdp2ColorRamReadLong(u32 addr) {
111    addr &= 0xFFF;
112    return T2ReadLong(Vdp2ColorRam, addr);
113 }
114 
115 //////////////////////////////////////////////////////////////////////////////
116 
Vdp2ColorRamWriteByte(u32 addr,u8 val)117 void FASTCALL Vdp2ColorRamWriteByte(u32 addr, u8 val) {
118    addr &= 0xFFF;
119    T2WriteByte(Vdp2ColorRam, addr, val);
120 }
121 
122 //////////////////////////////////////////////////////////////////////////////
123 
Vdp2ColorRamWriteWord(u32 addr,u16 val)124 void FASTCALL Vdp2ColorRamWriteWord(u32 addr, u16 val) {
125    addr &= 0xFFF;
126    T2WriteWord(Vdp2ColorRam, addr, val);
127 //   if (Vdp2Internal.ColorMode == 0)
128 //      T1WriteWord(Vdp2ColorRam, addr + 0x800, val);
129 }
130 
131 //////////////////////////////////////////////////////////////////////////////
132 
Vdp2ColorRamWriteLong(u32 addr,u32 val)133 void FASTCALL Vdp2ColorRamWriteLong(u32 addr, u32 val) {
134    addr &= 0xFFF;
135    T2WriteLong(Vdp2ColorRam, addr, val);
136 }
137 
138 //////////////////////////////////////////////////////////////////////////////
139 
Sh2Vdp2RamReadByte(SH2_struct * sh,u32 addr)140 u8 FASTCALL Sh2Vdp2RamReadByte(SH2_struct *sh, u32 addr) {
141    return Vdp2RamReadByte(addr);
142 }
143 
144 //////////////////////////////////////////////////////////////////////////////
145 
Sh2Vdp2RamReadWord(SH2_struct * sh,u32 addr)146 u16 FASTCALL Sh2Vdp2RamReadWord(SH2_struct *sh, u32 addr) {
147    return Vdp2RamReadWord(addr);
148 }
149 
150 //////////////////////////////////////////////////////////////////////////////
151 
Sh2Vdp2RamReadLong(SH2_struct * sh,u32 addr)152 u32 FASTCALL Sh2Vdp2RamReadLong(SH2_struct *sh, u32 addr) {
153    return Vdp2RamReadLong(addr);
154 }
155 
156 //////////////////////////////////////////////////////////////////////////////
157 
Sh2Vdp2RamWriteByte(SH2_struct * sh,u32 addr,u8 val)158 void FASTCALL Sh2Vdp2RamWriteByte(SH2_struct *sh, u32 addr, u8 val) {
159    Vdp2RamWriteByte(addr, val);
160 }
161 
162 //////////////////////////////////////////////////////////////////////////////
163 
Sh2Vdp2RamWriteWord(SH2_struct * sh,u32 addr,u16 val)164 void FASTCALL Sh2Vdp2RamWriteWord(SH2_struct *sh, u32 addr, u16 val) {
165    Vdp2RamWriteWord(addr, val);
166 }
167 
168 //////////////////////////////////////////////////////////////////////////////
169 
Sh2Vdp2RamWriteLong(SH2_struct * sh,u32 addr,u32 val)170 void FASTCALL Sh2Vdp2RamWriteLong(SH2_struct *sh, u32 addr, u32 val) {
171    Vdp2RamWriteLong(addr, val);
172 }
173 
174 //////////////////////////////////////////////////////////////////////////////
175 
Sh2Vdp2ColorRamReadByte(SH2_struct * sh,u32 addr)176 u8 FASTCALL Sh2Vdp2ColorRamReadByte(SH2_struct *sh, u32 addr) {
177    return Vdp2ColorRamReadByte(addr);
178 }
179 
180 //////////////////////////////////////////////////////////////////////////////
181 
Sh2Vdp2ColorRamReadWord(SH2_struct * sh,u32 addr)182 u16 FASTCALL Sh2Vdp2ColorRamReadWord(SH2_struct *sh, u32 addr) {
183    return Vdp2ColorRamReadWord(addr);
184 }
185 
186 //////////////////////////////////////////////////////////////////////////////
187 
Sh2Vdp2ColorRamReadLong(SH2_struct * sh,u32 addr)188 u32 FASTCALL Sh2Vdp2ColorRamReadLong(SH2_struct *sh, u32 addr) {
189    return Vdp2ColorRamReadLong(addr);
190 }
191 
192 //////////////////////////////////////////////////////////////////////////////
193 
Sh2Vdp2ColorRamWriteByte(SH2_struct * sh,u32 addr,u8 val)194 void FASTCALL Sh2Vdp2ColorRamWriteByte(SH2_struct *sh, u32 addr, u8 val) {
195    Vdp2ColorRamWriteByte(addr, val);
196 }
197 
198 //////////////////////////////////////////////////////////////////////////////
199 
Sh2Vdp2ColorRamWriteWord(SH2_struct * sh,u32 addr,u16 val)200 void FASTCALL Sh2Vdp2ColorRamWriteWord(SH2_struct *sh, u32 addr, u16 val) {
201    Vdp2ColorRamWriteWord(addr, val);
202 }
203 
204 //////////////////////////////////////////////////////////////////////////////
205 
Sh2Vdp2ColorRamWriteLong(SH2_struct * sh,u32 addr,u32 val)206 void FASTCALL Sh2Vdp2ColorRamWriteLong(SH2_struct *sh, u32 addr, u32 val) {
207    Vdp2ColorRamWriteLong(addr, val);
208 }
209 
210 //////////////////////////////////////////////////////////////////////////////
211 
Vdp2Init(void)212 int Vdp2Init(void) {
213    if ((Vdp2Regs = (Vdp2 *) calloc(1, sizeof(Vdp2))) == NULL)
214       return -1;
215 
216    if ((Vdp2Ram = T1MemoryInit(0x80000)) == NULL)
217       return -1;
218 
219    if ((Vdp2ColorRam = T2MemoryInit(0x1000)) == NULL)
220       return -1;
221 
222    Vdp2Reset();
223    return 0;
224 }
225 
226 //////////////////////////////////////////////////////////////////////////////
227 
Vdp2DeInit(void)228 void Vdp2DeInit(void) {
229    if (Vdp2Regs)
230       free(Vdp2Regs);
231    Vdp2Regs = NULL;
232 
233    if (Vdp2Ram)
234       T1MemoryDeInit(Vdp2Ram);
235    Vdp2Ram = NULL;
236 
237    if (Vdp2ColorRam)
238       T2MemoryDeInit(Vdp2ColorRam);
239    Vdp2ColorRam = NULL;
240 }
241 
242 //////////////////////////////////////////////////////////////////////////////
243 
Vdp2Reset(void)244 void Vdp2Reset(void) {
245    Vdp2Regs->TVMD = 0x0000;
246    Vdp2Regs->EXTEN = 0x0000;
247    Vdp2Regs->TVSTAT = Vdp2Regs->TVSTAT & 0x1;
248    Vdp2Regs->VRSIZE = 0x0000; // fix me(version should be set)
249    Vdp2Regs->RAMCTL = 0x0000;
250    Vdp2Regs->BGON = 0x0000;
251    Vdp2Regs->CHCTLA = 0x0000;
252    Vdp2Regs->CHCTLB = 0x0000;
253    Vdp2Regs->BMPNA = 0x0000;
254    Vdp2Regs->MPOFN = 0x0000;
255    Vdp2Regs->MPABN2 = 0x0000;
256    Vdp2Regs->MPCDN2 = 0x0000;
257    Vdp2Regs->SCXIN0 = 0x0000;
258    Vdp2Regs->SCXDN0 = 0x0000;
259    Vdp2Regs->SCYIN0 = 0x0000;
260    Vdp2Regs->SCYDN0 = 0x0000;
261    Vdp2Regs->ZMXN0.all = 0x00000000;
262    Vdp2Regs->ZMYN0.all = 0x00000000;
263    Vdp2Regs->SCXIN1 = 0x0000;
264    Vdp2Regs->SCXDN1 = 0x0000;
265    Vdp2Regs->SCYIN1 = 0x0000;
266    Vdp2Regs->SCYDN1 = 0x0000;
267    Vdp2Regs->ZMXN1.all = 0x00000000;
268    Vdp2Regs->ZMYN1.all = 0x00000000;
269    Vdp2Regs->SCXN2 = 0x0000;
270    Vdp2Regs->SCYN2 = 0x0000;
271    Vdp2Regs->SCXN3 = 0x0000;
272    Vdp2Regs->SCYN3 = 0x0000;
273    Vdp2Regs->ZMCTL = 0x0000;
274    Vdp2Regs->SCRCTL = 0x0000;
275    Vdp2Regs->VCSTA.all = 0x00000000;
276    Vdp2Regs->BKTAU = 0x0000;
277    Vdp2Regs->BKTAL = 0x0000;
278    Vdp2Regs->RPMD = 0x0000;
279    Vdp2Regs->RPRCTL = 0x0000;
280    Vdp2Regs->KTCTL = 0x0000;
281    Vdp2Regs->KTAOF = 0x0000;
282    Vdp2Regs->OVPNRA = 0x0000;
283    Vdp2Regs->OVPNRB = 0x0000;
284    Vdp2Regs->WPSX0 = 0x0000;
285    Vdp2Regs->WPSY0 = 0x0000;
286    Vdp2Regs->WPEX0 = 0x0000;
287    Vdp2Regs->WPEY0 = 0x0000;
288    Vdp2Regs->WPSX1 = 0x0000;
289    Vdp2Regs->WPSY1 = 0x0000;
290    Vdp2Regs->WPEX1 = 0x0000;
291    Vdp2Regs->WPEY1 = 0x0000;
292    Vdp2Regs->WCTLA = 0x0000;
293    Vdp2Regs->WCTLB = 0x0000;
294    Vdp2Regs->WCTLC = 0x0000;
295    Vdp2Regs->WCTLD = 0x0000;
296    Vdp2Regs->SPCTL = 0x0000;
297    Vdp2Regs->SDCTL = 0x0000;
298    Vdp2Regs->CRAOFA = 0x0000;
299    Vdp2Regs->CRAOFB = 0x0000;
300    Vdp2Regs->LNCLEN = 0x0000;
301    Vdp2Regs->SFPRMD = 0x0000;
302    Vdp2Regs->CCCTL = 0x0000;
303    Vdp2Regs->SFCCMD = 0x0000;
304    Vdp2Regs->PRISA = 0x0000;
305    Vdp2Regs->PRISB = 0x0000;
306    Vdp2Regs->PRISC = 0x0000;
307    Vdp2Regs->PRISD = 0x0000;
308    Vdp2Regs->PRINA = 0x0000;
309    Vdp2Regs->PRINB = 0x0000;
310    Vdp2Regs->PRIR = 0x0000;
311    Vdp2Regs->CCRNA = 0x0000;
312    Vdp2Regs->CCRNB = 0x0000;
313    Vdp2Regs->CLOFEN = 0x0000;
314    Vdp2Regs->CLOFSL = 0x0000;
315    Vdp2Regs->COAR = 0x0000;
316    Vdp2Regs->COAG = 0x0000;
317    Vdp2Regs->COAB = 0x0000;
318    Vdp2Regs->COBR = 0x0000;
319    Vdp2Regs->COBG = 0x0000;
320    Vdp2Regs->COBB = 0x0000;
321 
322    yabsys.VBlankLineCount = 225;
323    Vdp2Internal.ColorMode = 0;
324 
325    Vdp2External.disptoggle = 0xFF;
326 }
327 
328 //////////////////////////////////////////////////////////////////////////////
329 
Vdp2VBlankIN(void)330 void Vdp2VBlankIN(void) {
331    VIDCore->Vdp2DrawEnd();
332    /* this should be done after a frame change or a plot trigger */
333    Vdp1Regs->COPR = 0;
334 
335    /* I'm not 100% sure about this, but it seems that when using manual change
336    we should swap framebuffers in the "next field" and thus, clear the CEF...
337    now we're lying a little here as we're not swapping the framebuffers. */
338    if (Vdp1External.manualchange) Vdp1Regs->EDSR >>= 1;
339 
340    Vdp2Regs->TVSTAT |= 0x0008;
341    ScuSendVBlankIN();
342 
343    if (yabsys.IsSSH2Running)
344       SH2SendInterrupt(SSH2, 0x43, 0x6);
345 }
346 
347 //////////////////////////////////////////////////////////////////////////////
348 
Vdp2HBlankIN(void)349 void Vdp2HBlankIN(void) {
350    Vdp2Regs->TVSTAT |= 0x0004;
351    ScuSendHBlankIN();
352 
353    if (yabsys.IsSSH2Running)
354       SH2SendInterrupt(SSH2, 0x41, 0x2);
355 }
356 
357 //////////////////////////////////////////////////////////////////////////////
358 
Vdp2HBlankOUT(void)359 void Vdp2HBlankOUT(void) {
360    int i;
361    Vdp2Regs->TVSTAT &= ~0x0004;
362 
363    if (yabsys.LineCount < 270)
364    {
365       u32 cell_scroll_table_start_addr = (Vdp2Regs->VCSTA.all & 0x7FFFE) << 1;
366       memcpy(Vdp2Lines + yabsys.LineCount, Vdp2Regs, sizeof(Vdp2));
367 
368       for (i = 0; i < 88; i++)
369       {
370          cell_scroll_data[yabsys.LineCount].data[i] = T1ReadLong(Vdp2Ram, cell_scroll_table_start_addr + i * 4);
371       }
372    }
373 }
374 
375 //////////////////////////////////////////////////////////////////////////////
376 
Vdp2RestoreRegs(int line,Vdp2 * lines)377 Vdp2 * Vdp2RestoreRegs(int line, Vdp2* lines) {
378    return line > 270 ? NULL : lines + line;
379 }
380 
381 //////////////////////////////////////////////////////////////////////////////
382 
FPSDisplay(void)383 static void FPSDisplay(void)
384 {
385    static int fpsframecount = 0;
386    static u64 fpsticks;
387 
388    OSDPushMessage(OSDMSG_FPS, 1, "%02d/%02d FPS", fps, yabsys.IsPal ? 50 : 60);
389    OSDPushMessage(OSDMSG_DEBUG, 1, "%d %d %s %s", framecounter, lagframecounter, MovieStatus, InputDisplayString);
390    fpsframecount++;
391    if(YabauseGetTicks() >= fpsticks + yabsys.tickfreq)
392    {
393       fps = fpsframecount;
394       fpsframecount = 0;
395       fpsticks = YabauseGetTicks();
396    }
397 }
398 
399 //////////////////////////////////////////////////////////////////////////////
400 
SpeedThrottleEnable(void)401 void SpeedThrottleEnable(void) {
402    throttlespeed = 1;
403 }
404 
405 //////////////////////////////////////////////////////////////////////////////
406 
SpeedThrottleDisable(void)407 void SpeedThrottleDisable(void) {
408    throttlespeed = 0;
409 }
410 
411 //////////////////////////////////////////////////////////////////////////////
412 
Vdp2VBlankOUT(void)413 void Vdp2VBlankOUT(void) {
414    static int framestoskip = 0;
415    static int framesskipped = 0;
416    static int skipnextframe = 0;
417    static u64 curticks = 0;
418    static u64 diffticks = 0;
419    static u32 framecount = 0;
420    static u64 onesecondticks = 0;
421    static VideoInterface_struct * saved = NULL;
422 
423    if (vdp2_is_odd_frame)
424       vdp2_is_odd_frame = 0;
425    else
426       vdp2_is_odd_frame = 1;
427 
428    Vdp2Regs->TVSTAT = ((Vdp2Regs->TVSTAT & ~0x0008) & ~0x0002) | (vdp2_is_odd_frame << 1);
429 
430    if (skipnextframe && (! saved))
431    {
432       saved = VIDCore;
433       VIDCore = &VIDDummy;
434    }
435    else if (saved && (! skipnextframe))
436    {
437       VIDCore = saved;
438       saved = NULL;
439    }
440 
441    VIDCore->Vdp2DrawStart();
442 
443    if (Vdp2Regs->TVMD & 0x8000) {
444       VIDCore->Vdp2DrawScreens();
445       if (Vdp1Regs->PTMR == 2) Vdp1Draw();
446    }
447    else
448    {
449       VIDCore->Vdp2DispOff();
450       if (Vdp1Regs->PTMR == 2) Vdp1Draw();
451    }
452 
453    FPSDisplay();
454    if ((Vdp1Regs->FBCR & 2) && (Vdp1Regs->TVMR & 8))
455       Vdp1External.manualerase = 1;
456 
457    if (!skipnextframe)
458    {
459       framesskipped = 0;
460 
461       if (framestoskip > 0)
462          skipnextframe = 1;
463    }
464    else
465    {
466       framestoskip--;
467 
468       if (framestoskip < 1)
469          skipnextframe = 0;
470       else
471          skipnextframe = 1;
472 
473       framesskipped++;
474    }
475 
476    // Do Frame Skip/Frame Limiting/Speed Throttling here
477    if (throttlespeed)
478    {
479       // Should really depend on how fast we're rendering the frames
480       if (framestoskip < 1)
481          framestoskip = 6;
482    }
483    //when in frame advance, disable frame skipping
484    else if (autoframeskipenab && FrameAdvanceVariable == 0)
485    {
486       framecount++;
487 
488       if (framecount > (yabsys.IsPal ? 50 : 60))
489       {
490          framecount = 1;
491          onesecondticks = 0;
492       }
493 
494       curticks = YabauseGetTicks();
495       diffticks = curticks-lastticks;
496 
497       if ((onesecondticks+diffticks) > ((yabsys.OneFrameTime * (u64)framecount) + (yabsys.OneFrameTime / 2)) &&
498           framesskipped < 9)
499       {
500          // Skip the next frame
501          skipnextframe = 1;
502 
503          // How many frames should we skip?
504          framestoskip = 1;
505       }
506       else if ((onesecondticks+diffticks) < ((yabsys.OneFrameTime * (u64)framecount) - (yabsys.OneFrameTime / 2)))
507       {
508          // Check to see if we need to limit speed at all
509          for (;;)
510          {
511             curticks = YabauseGetTicks();
512             diffticks = curticks-lastticks;
513             if ((onesecondticks+diffticks) >= (yabsys.OneFrameTime * (u64)framecount))
514                break;
515          }
516       }
517 
518       onesecondticks += diffticks;
519       lastticks = curticks;
520    }
521 
522    ScuSendVBlankOUT();
523 
524    if (Vdp2Regs->EXTEN & 0x200) // Should be revised for accuracy(should occur only occur on the line it happens at, etc.)
525    {
526       // Only Latch if EXLTEN is enabled
527       if (SmpcRegs->EXLE & 0x1)
528          Vdp2SendExternalLatch((PORTDATA1.data[3]<<8)|PORTDATA1.data[4], (PORTDATA1.data[5]<<8)|PORTDATA1.data[6]);
529 	}
530 }
531 
532 //////////////////////////////////////////////////////////////////////////////
533 
Vdp2SendExternalLatch(int hcnt,int vcnt)534 void Vdp2SendExternalLatch(int hcnt, int vcnt)
535 {
536    Vdp2Regs->HCNT = hcnt << 1;
537    Vdp2Regs->VCNT = vcnt;
538    Vdp2Regs->TVSTAT |= 0x200;
539 }
540 
541 //////////////////////////////////////////////////////////////////////////////
542 
Vdp2ReadByte(u32 addr)543 u8 FASTCALL Vdp2ReadByte(u32 addr) {
544    LOG("VDP2 register byte read = %08X\n", addr);
545    addr &= 0x1FF;
546    return 0;
547 }
548 
549 //////////////////////////////////////////////////////////////////////////////
550 
Vdp2ReadWord(u32 addr)551 u16 FASTCALL Vdp2ReadWord(u32 addr) {
552    addr &= 0x1FF;
553 
554    switch (addr)
555    {
556       case 0x000:
557          return Vdp2Regs->TVMD;
558       case 0x002:
559          if (!(Vdp2Regs->EXTEN & 0x200))
560          {
561             // Latch HV counter on read
562             // Vdp2Regs->HCNT = ?;
563             Vdp2Regs->VCNT = yabsys.LineCount;
564             Vdp2Regs->TVSTAT |= 0x200;
565          }
566 
567          return Vdp2Regs->EXTEN;
568       case 0x004:
569       {
570          u16 tvstat = Vdp2Regs->TVSTAT;
571 
572          // Clear External latch and sync flags
573          Vdp2Regs->TVSTAT &= 0xFCFF;
574 
575          // if TVMD's DISP bit is cleared, TVSTAT's VBLANK bit is always set
576          if (Vdp2Regs->TVMD & 0x8000)
577             return tvstat;
578          else
579             return (tvstat | 0x8);
580       }
581       case 0x006:
582          return Vdp2Regs->VRSIZE;
583       case 0x008:
584          return Vdp2Regs->HCNT;
585       case 0x00A:
586          return Vdp2Regs->VCNT;
587       default:
588       {
589          LOG("Unhandled VDP2 word read: %08X\n", addr);
590          break;
591       }
592    }
593 
594    return 0;
595 }
596 
597 //////////////////////////////////////////////////////////////////////////////
598 
Vdp2ReadLong(u32 addr)599 u32 FASTCALL Vdp2ReadLong(u32 addr) {
600    LOG("VDP2 register long read = %08X\n", addr);
601    addr &= 0x1FF;
602    return 0;
603 }
604 
605 //////////////////////////////////////////////////////////////////////////////
606 
Vdp2WriteByte(u32 addr,UNUSED u8 val)607 void FASTCALL Vdp2WriteByte(u32 addr, UNUSED u8 val) {
608    LOG("VDP2 register byte write = %08X\n", addr);
609    addr &= 0x1FF;
610 }
611 
612 //////////////////////////////////////////////////////////////////////////////
613 
Vdp2WriteWord(u32 addr,u16 val)614 void FASTCALL Vdp2WriteWord(u32 addr, u16 val) {
615    addr &= 0x1FF;
616 
617    switch (addr)
618    {
619       case 0x000:
620          Vdp2Regs->TVMD = val;
621          yabsys.VBlankLineCount = 225+(val & 0x30);
622          return;
623       case 0x002:
624          Vdp2Regs->EXTEN = val;
625          return;
626       case 0x004:
627          // TVSTAT is read-only
628          return;
629       case 0x006:
630          Vdp2Regs->VRSIZE = val;
631          return;
632       case 0x008:
633          // HCNT is read-only
634          return;
635       case 0x00A:
636          // VCNT is read-only
637          return;
638       case 0x00C:
639          // Reserved
640          return;
641       case 0x00E:
642          Vdp2Regs->RAMCTL = val;
643          Vdp2Internal.ColorMode = (val >> 12) & 0x3;
644          return;
645       case 0x010:
646          Vdp2Regs->CYCA0L = val;
647          return;
648       case 0x012:
649          Vdp2Regs->CYCA0U = val;
650          return;
651       case 0x014:
652          Vdp2Regs->CYCA1L = val;
653          return;
654       case 0x016:
655          Vdp2Regs->CYCA1U = val;
656          return;
657       case 0x018:
658          Vdp2Regs->CYCB0L = val;
659          return;
660       case 0x01A:
661          Vdp2Regs->CYCB0U = val;
662          return;
663       case 0x01C:
664          Vdp2Regs->CYCB1L = val;
665          return;
666       case 0x01E:
667          Vdp2Regs->CYCB1U = val;
668          return;
669       case 0x020:
670          Vdp2Regs->BGON = val;
671          return;
672       case 0x022:
673          Vdp2Regs->MZCTL = val;
674          return;
675       case 0x024:
676          Vdp2Regs->SFSEL = val;
677          return;
678       case 0x026:
679          Vdp2Regs->SFCODE = val;
680          return;
681       case 0x028:
682          Vdp2Regs->CHCTLA = val;
683          return;
684       case 0x02A:
685          Vdp2Regs->CHCTLB = val;
686          return;
687       case 0x02C:
688          Vdp2Regs->BMPNA = val;
689          return;
690       case 0x02E:
691          Vdp2Regs->BMPNB = val;
692          return;
693       case 0x030:
694          Vdp2Regs->PNCN0 = val;
695          return;
696       case 0x032:
697          Vdp2Regs->PNCN1 = val;
698          return;
699       case 0x034:
700          Vdp2Regs->PNCN2 = val;
701          return;
702       case 0x036:
703          Vdp2Regs->PNCN3 = val;
704          return;
705       case 0x038:
706          Vdp2Regs->PNCR = val;
707          return;
708       case 0x03A:
709          Vdp2Regs->PLSZ = val;
710          return;
711       case 0x03C:
712          Vdp2Regs->MPOFN = val;
713          return;
714       case 0x03E:
715          Vdp2Regs->MPOFR = val;
716          return;
717       case 0x040:
718          Vdp2Regs->MPABN0 = val;
719          return;
720       case 0x042:
721          Vdp2Regs->MPCDN0 = val;
722          return;
723       case 0x044:
724          Vdp2Regs->MPABN1 = val;
725          return;
726       case 0x046:
727          Vdp2Regs->MPCDN1 = val;
728          return;
729       case 0x048:
730          Vdp2Regs->MPABN2 = val;
731          return;
732       case 0x04A:
733          Vdp2Regs->MPCDN2 = val;
734          return;
735       case 0x04C:
736          Vdp2Regs->MPABN3 = val;
737          return;
738       case 0x04E:
739          Vdp2Regs->MPCDN3 = val;
740          return;
741       case 0x050:
742          Vdp2Regs->MPABRA = val;
743          return;
744       case 0x052:
745          Vdp2Regs->MPCDRA = val;
746          return;
747       case 0x054:
748          Vdp2Regs->MPEFRA = val;
749          return;
750       case 0x056:
751          Vdp2Regs->MPGHRA = val;
752          return;
753       case 0x058:
754          Vdp2Regs->MPIJRA = val;
755          return;
756       case 0x05A:
757          Vdp2Regs->MPKLRA = val;
758          return;
759       case 0x05C:
760          Vdp2Regs->MPMNRA = val;
761          return;
762       case 0x05E:
763          Vdp2Regs->MPOPRA = val;
764          return;
765       case 0x060:
766          Vdp2Regs->MPABRB = val;
767          return;
768       case 0x062:
769          Vdp2Regs->MPCDRB = val;
770          return;
771       case 0x064:
772          Vdp2Regs->MPEFRB = val;
773          return;
774       case 0x066:
775          Vdp2Regs->MPGHRB = val;
776          return;
777       case 0x068:
778          Vdp2Regs->MPIJRB = val;
779          return;
780       case 0x06A:
781          Vdp2Regs->MPKLRB = val;
782          return;
783       case 0x06C:
784          Vdp2Regs->MPMNRB = val;
785          return;
786       case 0x06E:
787          Vdp2Regs->MPOPRB = val;
788          return;
789       case 0x070:
790          Vdp2Regs->SCXIN0 = val;
791          return;
792       case 0x072:
793          Vdp2Regs->SCXDN0 = val;
794          return;
795       case 0x074:
796          Vdp2Regs->SCYIN0 = val;
797          return;
798       case 0x076:
799          Vdp2Regs->SCYDN0 = val;
800          return;
801       case 0x078:
802          Vdp2Regs->ZMXN0.part.I = val;
803          return;
804       case 0x07A:
805          Vdp2Regs->ZMXN0.part.D = val;
806          return;
807       case 0x07C:
808          Vdp2Regs->ZMYN0.part.I = val;
809          return;
810       case 0x07E:
811          Vdp2Regs->ZMYN0.part.D = val;
812          return;
813       case 0x080:
814          Vdp2Regs->SCXIN1 = val;
815          return;
816       case 0x082:
817          Vdp2Regs->SCXDN1 = val;
818          return;
819       case 0x084:
820          Vdp2Regs->SCYIN1 = val;
821          return;
822       case 0x086:
823          Vdp2Regs->SCYDN1 = val;
824          return;
825       case 0x088:
826          Vdp2Regs->ZMXN1.part.I = val;
827          return;
828       case 0x08A:
829          Vdp2Regs->ZMXN1.part.D = val;
830          return;
831       case 0x08C:
832          Vdp2Regs->ZMYN1.part.I = val;
833          return;
834       case 0x08E:
835          Vdp2Regs->ZMYN1.part.D = val;
836          return;
837       case 0x090:
838          Vdp2Regs->SCXN2 = val;
839          return;
840       case 0x092:
841          Vdp2Regs->SCYN2 = val;
842          return;
843       case 0x094:
844          Vdp2Regs->SCXN3 = val;
845          return;
846       case 0x096:
847          Vdp2Regs->SCYN3 = val;
848          return;
849       case 0x098:
850          Vdp2Regs->ZMCTL = val;
851          return;
852       case 0x09A:
853          Vdp2Regs->SCRCTL = val;
854          return;
855       case 0x09C:
856          Vdp2Regs->VCSTA.part.U = val;
857          return;
858       case 0x09E:
859          Vdp2Regs->VCSTA.part.L = val;
860          return;
861       case 0x0A0:
862          Vdp2Regs->LSTA0.part.U = val;
863          return;
864       case 0x0A2:
865          Vdp2Regs->LSTA0.part.L = val;
866          return;
867       case 0x0A4:
868          Vdp2Regs->LSTA1.part.U = val;
869          return;
870       case 0x0A6:
871          Vdp2Regs->LSTA1.part.L = val;
872          return;
873       case 0x0A8:
874          Vdp2Regs->LCTA.part.U = val;
875          return;
876       case 0x0AA:
877          Vdp2Regs->LCTA.part.L = val;
878          return;
879       case 0x0AC:
880          Vdp2Regs->BKTAU = val;
881          return;
882       case 0x0AE:
883          Vdp2Regs->BKTAL = val;
884          return;
885       case 0x0B0:
886          Vdp2Regs->RPMD = val;
887          return;
888       case 0x0B2:
889          Vdp2Regs->RPRCTL = val;
890          return;
891       case 0x0B4:
892          Vdp2Regs->KTCTL = val;
893          return;
894       case 0x0B6:
895          Vdp2Regs->KTAOF = val;
896          return;
897       case 0x0B8:
898          Vdp2Regs->OVPNRA = val;
899          return;
900       case 0x0BA:
901          Vdp2Regs->OVPNRB = val;
902          return;
903       case 0x0BC:
904          Vdp2Regs->RPTA.part.U = val;
905          return;
906       case 0x0BE:
907          Vdp2Regs->RPTA.part.L = val;
908          return;
909       case 0x0C0:
910          Vdp2Regs->WPSX0 = val;
911          return;
912       case 0x0C2:
913          Vdp2Regs->WPSY0 = val;
914          return;
915       case 0x0C4:
916          Vdp2Regs->WPEX0 = val;
917          return;
918       case 0x0C6:
919          Vdp2Regs->WPEY0 = val;
920          return;
921       case 0x0C8:
922          Vdp2Regs->WPSX1 = val;
923          return;
924       case 0x0CA:
925          Vdp2Regs->WPSY1 = val;
926          return;
927       case 0x0CC:
928          Vdp2Regs->WPEX1 = val;
929          return;
930       case 0x0CE:
931          Vdp2Regs->WPEY1 = val;
932          return;
933       case 0x0D0:
934          Vdp2Regs->WCTLA = val;
935          return;
936       case 0x0D2:
937          Vdp2Regs->WCTLB = val;
938          return;
939       case 0x0D4:
940          Vdp2Regs->WCTLC = val;
941          return;
942       case 0x0D6:
943          Vdp2Regs->WCTLD = val;
944          return;
945       case 0x0D8:
946          Vdp2Regs->LWTA0.part.U = val;
947          return;
948       case 0x0DA:
949          Vdp2Regs->LWTA0.part.L = val;
950          return;
951       case 0x0DC:
952          Vdp2Regs->LWTA1.part.U = val;
953          return;
954       case 0x0DE:
955          Vdp2Regs->LWTA1.part.L = val;
956          return;
957       case 0x0E0:
958          Vdp2Regs->SPCTL = val;
959          return;
960       case 0x0E2:
961          Vdp2Regs->SDCTL = val;
962          return;
963       case 0x0E4:
964          Vdp2Regs->CRAOFA = val;
965          return;
966       case 0x0E6:
967          Vdp2Regs->CRAOFB = val;
968          return;
969       case 0x0E8:
970          Vdp2Regs->LNCLEN = val;
971          return;
972       case 0x0EA:
973          Vdp2Regs->SFPRMD = val;
974          return;
975       case 0x0EC:
976          Vdp2Regs->CCCTL = val;
977          return;
978       case 0x0EE:
979          Vdp2Regs->SFCCMD = val;
980          return;
981       case 0x0F0:
982          Vdp2Regs->PRISA = val;
983          return;
984       case 0x0F2:
985          Vdp2Regs->PRISB = val;
986          return;
987       case 0x0F4:
988          Vdp2Regs->PRISC = val;
989          return;
990       case 0x0F6:
991          Vdp2Regs->PRISD = val;
992          return;
993       case 0x0F8:
994          Vdp2Regs->PRINA = val;
995          return;
996       case 0x0FA:
997          Vdp2Regs->PRINB = val;
998          return;
999       case 0x0FC:
1000          Vdp2Regs->PRIR = val;
1001          return;
1002       case 0x0FE:
1003          // Reserved
1004          return;
1005       case 0x100:
1006          Vdp2Regs->CCRSA = val;
1007          return;
1008       case 0x102:
1009          Vdp2Regs->CCRSB = val;
1010          return;
1011       case 0x104:
1012          Vdp2Regs->CCRSC = val;
1013          return;
1014       case 0x106:
1015          Vdp2Regs->CCRSD = val;
1016          return;
1017       case 0x108:
1018          Vdp2Regs->CCRNA = val;
1019          return;
1020       case 0x10A:
1021          Vdp2Regs->CCRNB = val;
1022          return;
1023       case 0x10C:
1024          Vdp2Regs->CCRR = val;
1025          return;
1026       case 0x10E:
1027          Vdp2Regs->CCRLB = val;
1028          return;
1029       case 0x110:
1030          Vdp2Regs->CLOFEN = val;
1031          return;
1032       case 0x112:
1033          Vdp2Regs->CLOFSL = val;
1034          return;
1035       case 0x114:
1036          Vdp2Regs->COAR = val;
1037          return;
1038       case 0x116:
1039          Vdp2Regs->COAG = val;
1040          return;
1041       case 0x118:
1042          Vdp2Regs->COAB = val;
1043          return;
1044       case 0x11A:
1045          Vdp2Regs->COBR = val;
1046          return;
1047       case 0x11C:
1048          Vdp2Regs->COBG = val;
1049          return;
1050       case 0x11E:
1051          Vdp2Regs->COBB = val;
1052          return;
1053       default:
1054       {
1055          LOG("Unhandled VDP2 word write: %08X\n", addr);
1056          break;
1057       }
1058    }
1059 }
1060 
1061 //////////////////////////////////////////////////////////////////////////////
1062 
Vdp2WriteLong(u32 addr,u32 val)1063 void FASTCALL Vdp2WriteLong(u32 addr, u32 val) {
1064 
1065    Vdp2WriteWord(addr,val>>16);
1066    Vdp2WriteWord(addr+2,val&0xFFFF);
1067    return;
1068 }
1069 
1070 //////////////////////////////////////////////////////////////////////////////
1071 
Sh2Vdp2ReadByte(SH2_struct * sh,u32 addr)1072 u8 FASTCALL Sh2Vdp2ReadByte(SH2_struct *sh, u32 addr) {
1073    return Vdp2ReadByte(addr);
1074 }
1075 
1076 //////////////////////////////////////////////////////////////////////////////
1077 
Sh2Vdp2ReadWord(SH2_struct * sh,u32 addr)1078 u16 FASTCALL Sh2Vdp2ReadWord(SH2_struct *sh, u32 addr) {
1079    return Vdp2ReadWord(addr);
1080 }
1081 
1082 //////////////////////////////////////////////////////////////////////////////
1083 
Sh2Vdp2ReadLong(SH2_struct * sh,u32 addr)1084 u32 FASTCALL Sh2Vdp2ReadLong(SH2_struct *sh, u32 addr) {
1085    return Vdp2ReadLong(addr);
1086 }
1087 
1088 //////////////////////////////////////////////////////////////////////////////
1089 
Sh2Vdp2WriteByte(SH2_struct * sh,u32 addr,UNUSED u8 val)1090 void FASTCALL Sh2Vdp2WriteByte(SH2_struct *sh, u32 addr, UNUSED u8 val) {
1091    Vdp2WriteByte(addr, val);
1092 }
1093 
1094 //////////////////////////////////////////////////////////////////////////////
1095 
Sh2Vdp2WriteWord(SH2_struct * sh,u32 addr,u16 val)1096 void FASTCALL Sh2Vdp2WriteWord(SH2_struct *sh, u32 addr, u16 val) {
1097    Vdp2WriteWord(addr, val);
1098 }
1099 
1100 //////////////////////////////////////////////////////////////////////////////
1101 
Sh2Vdp2WriteLong(SH2_struct * sh,u32 addr,u32 val)1102 void FASTCALL Sh2Vdp2WriteLong(SH2_struct *sh, u32 addr, u32 val) {
1103    Vdp2WriteLong(addr, val);
1104 }
1105 
1106 //////////////////////////////////////////////////////////////////////////////
1107 
Vdp2SaveState(FILE * fp)1108 int Vdp2SaveState(FILE *fp)
1109 {
1110    int offset;
1111    IOCheck_struct check = { 0, 0 };
1112 
1113    offset = StateWriteHeader(fp, "VDP2", 1);
1114 
1115    // Write registers
1116    ywrite(&check, (void *)Vdp2Regs, sizeof(Vdp2), 1, fp);
1117 
1118    // Write VDP2 ram
1119    ywrite(&check, (void *)Vdp2Ram, 0x80000, 1, fp);
1120 
1121    // Write CRAM
1122    ywrite(&check, (void *)Vdp2ColorRam, 0x1000, 1, fp);
1123 
1124    // Write internal variables
1125    ywrite(&check, (void *)&Vdp2Internal, sizeof(Vdp2Internal_struct), 1, fp);
1126 
1127    return StateFinishHeader(fp, offset);
1128 }
1129 
1130 //////////////////////////////////////////////////////////////////////////////
1131 
Vdp2LoadState(FILE * fp,UNUSED int version,int size)1132 int Vdp2LoadState(FILE *fp, UNUSED int version, int size)
1133 {
1134    IOCheck_struct check = { 0, 0 };
1135 
1136    // Read registers
1137    yread(&check, (void *)Vdp2Regs, sizeof(Vdp2), 1, fp);
1138 
1139    // Read VDP2 ram
1140    yread(&check, (void *)Vdp2Ram, 0x80000, 1, fp);
1141 
1142    // Read CRAM
1143    yread(&check, (void *)Vdp2ColorRam, 0x1000, 1, fp);
1144 
1145    // Read internal variables
1146    yread(&check, (void *)&Vdp2Internal, sizeof(Vdp2Internal_struct), 1, fp);
1147 
1148    return size;
1149 }
1150 
1151 //////////////////////////////////////////////////////////////////////////////
1152 
ToggleNBG0(void)1153 void ToggleNBG0(void)
1154 {
1155    Vdp2External.disptoggle ^= 0x1;
1156 }
1157 
1158 //////////////////////////////////////////////////////////////////////////////
1159 
ToggleNBG1(void)1160 void ToggleNBG1(void)
1161 {
1162    Vdp2External.disptoggle ^= 0x2;
1163 }
1164 
1165 //////////////////////////////////////////////////////////////////////////////
1166 
ToggleNBG2(void)1167 void ToggleNBG2(void)
1168 {
1169    Vdp2External.disptoggle ^= 0x4;
1170 }
1171 
1172 //////////////////////////////////////////////////////////////////////////////
1173 
ToggleNBG3(void)1174 void ToggleNBG3(void)
1175 {
1176    Vdp2External.disptoggle ^= 0x8;
1177 }
1178 
1179 //////////////////////////////////////////////////////////////////////////////
1180 
ToggleRBG0(void)1181 void ToggleRBG0(void)
1182 {
1183    Vdp2External.disptoggle ^= 0x10;
1184 }
1185 
1186 //////////////////////////////////////////////////////////////////////////////
1187 
ToggleFullScreen(void)1188 void ToggleFullScreen(void)
1189 {
1190    if (VIDCore->IsFullscreen())
1191    {
1192       VIDCore->Resize(320, 224, 0);
1193    }
1194    else
1195    {
1196       VIDCore->Resize(640, 480, 1);
1197    }
1198 }
1199 
1200 //////////////////////////////////////////////////////////////////////////////
1201 
EnableAutoFrameSkip(void)1202 void EnableAutoFrameSkip(void)
1203 {
1204    autoframeskipenab = 1;
1205    lastticks = YabauseGetTicks();
1206 }
1207 
1208 //////////////////////////////////////////////////////////////////////////////
1209 
DisableAutoFrameSkip(void)1210 void DisableAutoFrameSkip(void)
1211 {
1212    autoframeskipenab = 0;
1213 }
1214 
1215 //////////////////////////////////////////////////////////////////////////////
1216