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