1/*****************************************************************************\
2 Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3 This file is licensed under the Snes9x License.
4 For further information, consult the LICENSE file in the root directory.
5\*****************************************************************************/
6
7#include "snes9x.h"
8#include "memmap.h"
9#include "fxinst.h"
10#include "fxemu.h"
11
12static void FxReset (struct FxInfo_s *);
13static void fx_readRegisterSpace (void);
14static void fx_writeRegisterSpace (void);
15static void fx_updateRamBank (uint8);
16static void fx_dirtySCBR (void);
17static bool8 fx_checkStartAddress (void);
18static uint32 FxEmulate (uint32);
19static void FxCacheWriteAccess (uint16);
20static void FxFlushCache (void);
21
22
23void S9xInitSuperFX (void)
24{
25 memset((uint8 *) &GSU, 0, sizeof(struct FxRegs_s));
26}
27
28void S9xResetSuperFX (void)
29{
30 // FIXME: Snes9x only runs the SuperFX at the end of every line.
31 // 5823405 is a magic number that seems to work for most games.
32 SuperFX.speedPerLine = (uint32) (5823405 * ((1.0 / (float) Memory.ROMFramesPerSecond) / ((float) (Timings.V_Max))));
33 SuperFX.oneLineDone = FALSE;
34 SuperFX.vFlags = 0;
35 CPU.IRQExternal = FALSE;
36 FxReset(&SuperFX);
37}
38
39void S9xSetSuperFX (uint8 byte, uint16 address)
40{
41 switch (address)
42 {
43 case 0x3030:
44 if ((Memory.FillRAM[0x3030] ^ byte) & FLG_G)
45 {
46 Memory.FillRAM[0x3030] = byte;
47 if (byte & FLG_G)
48 {
49 if (!SuperFX.oneLineDone)
50 {
51 S9xSuperFXExec();
52 SuperFX.oneLineDone = TRUE;
53 }
54 }
55 else
56 FxFlushCache();
57 }
58 else
59 Memory.FillRAM[0x3030] = byte;
60
61 break;
62
63 case 0x3031:
64 Memory.FillRAM[0x3031] = byte;
65 break;
66
67 case 0x3033:
68 Memory.FillRAM[0x3033] = byte;
69 break;
70
71 case 0x3034:
72 Memory.FillRAM[0x3034] = byte & 0x7f;
73 break;
74
75 case 0x3036:
76 Memory.FillRAM[0x3036] = byte & 0x7f;
77 break;
78
79 case 0x3037:
80 Memory.FillRAM[0x3037] = byte;
81 break;
82
83 case 0x3038:
84 Memory.FillRAM[0x3038] = byte;
85 fx_dirtySCBR();
86 break;
87
88 case 0x3039:
89 Memory.FillRAM[0x3039] = byte;
90 break;
91
92 case 0x303a:
93 Memory.FillRAM[0x303a] = byte;
94 break;
95
96 case 0x303b:
97 break;
98
99 case 0x303c:
100 Memory.FillRAM[0x303c] = byte;
101 fx_updateRamBank(byte);
102 break;
103
104 case 0x303f:
105 Memory.FillRAM[0x303f] = byte;
106 break;
107
108 case 0x301f:
109 Memory.FillRAM[0x301f] = byte;
110 Memory.FillRAM[0x3000 + GSU_SFR] |= FLG_G;
111 if (!SuperFX.oneLineDone)
112 {
113 S9xSuperFXExec();
114 SuperFX.oneLineDone = TRUE;
115 }
116
117 break;
118
119 default:
120 Memory.FillRAM[address] = byte;
121 if (address >= 0x3100)
122 FxCacheWriteAccess(address);
123
124 break;
125 }
126}
127
128uint8 S9xGetSuperFX (uint16 address)
129{
130 uint8 byte;
131
132 byte = Memory.FillRAM[address];
133
134 if (address == 0x3031)
135 {
136 CPU.IRQExternal = FALSE;
137 Memory.FillRAM[0x3031] = byte & 0x7f;
138 }
139
140 return (byte);
141}
142
143void S9xSuperFXExec (void)
144{
145 if ((Memory.FillRAM[0x3000 + GSU_SFR] & FLG_G) && (Memory.FillRAM[0x3000 + GSU_SCMR] & 0x18) == 0x18)
146 {
147 FxEmulate(((Memory.FillRAM[0x3000 + GSU_CLSR] & 1) ? (SuperFX.speedPerLine * 5 / 2) : SuperFX.speedPerLine) * Settings.SuperFXClockMultiplier / 100);
148
149 uint16 GSUStatus = Memory.FillRAM[0x3000 + GSU_SFR] | (Memory.FillRAM[0x3000 + GSU_SFR + 1] << 8);
150 if ((GSUStatus & (FLG_G | FLG_IRQ)) == FLG_IRQ)
151 CPU.IRQExternal = TRUE;
152 }
153}
154
155static void FxReset (struct FxInfo_s *psFxInfo)
156{
157 // Clear all internal variables
158 memset((uint8 *) &GSU, 0, sizeof(struct FxRegs_s));
159
160 // Set default registers
161 GSU.pvSreg = GSU.pvDreg = &R0;
162
163 // Set RAM and ROM pointers
164 GSU.pvRegisters = psFxInfo->pvRegisters;
165 GSU.nRamBanks = psFxInfo->nRamBanks;
166 GSU.pvRam = psFxInfo->pvRam;
167 GSU.nRomBanks = psFxInfo->nRomBanks;
168 GSU.pvRom = psFxInfo->pvRom;
169 GSU.vPrevScreenHeight = ~0;
170 GSU.vPrevMode = ~0;
171
172 // The GSU can't access more than 2mb (16mbits)
173 if (GSU.nRomBanks > 0x20)
174 GSU.nRomBanks = 0x20;
175
176 // Clear FxChip register space
177 memset(GSU.pvRegisters, 0, 0x300);
178
179 // Set FxChip version Number
180 GSU.pvRegisters[0x3b] = 0;
181
182 // Make ROM bank table
183 for (int i = 0; i < 256; i++)
184 {
185 uint32 b = i & 0x7f;
186
187 if (b >= 0x40)
188 {
189 if (GSU.nRomBanks > 1)
190 b %= GSU.nRomBanks;
191 else
192 b &= 1;
193
194 GSU.apvRomBank[i] = &GSU.pvRom[b << 16];
195 }
196 else
197 {
198 b %= GSU.nRomBanks * 2;
199 GSU.apvRomBank[i] = &GSU.pvRom[(b << 16) + 0x200000];
200 }
201 }
202
203 // Make RAM bank table
204 for (int i = 0; i < 4; i++)
205 {
206 GSU.apvRamBank[i] = &GSU.pvRam[(i % GSU.nRamBanks) << 16];
207 GSU.apvRomBank[0x70 + i] = GSU.apvRamBank[i];
208 }
209
210 // Start with a nop in the pipe
211 GSU.vPipe = 0x01;
212
213 // Set pointer to GSU cache
214 GSU.pvCache = &GSU.pvRegisters[0x100];
215
216 fx_readRegisterSpace();
217}
218
219static void fx_readRegisterSpace (void)
220{
221 static uint32 avHeight[] = { 128, 160, 192, 256 };
222 static uint32 avMult[] = { 16, 32, 32, 64 };
223
224 uint8 *p;
225 int n;
226
227 GSU.vErrorCode = 0;
228
229 // Update R0-R15
230 p = GSU.pvRegisters;
231 for (int i = 0; i < 16; i++)
232 {
233 GSU.avReg[i] = *p++;
234 GSU.avReg[i] += ((uint32) (*p++)) << 8;
235 }
236
237 // Update other registers
238 p = GSU.pvRegisters;
239 GSU.vStatusReg = (uint32) p[GSU_SFR];
240 GSU.vStatusReg |= ((uint32) p[GSU_SFR + 1]) << 8;
241 GSU.vPrgBankReg = (uint32) p[GSU_PBR];
242 GSU.vRomBankReg = (uint32) p[GSU_ROMBR];
243 GSU.vRamBankReg = ((uint32) p[GSU_RAMBR]) & (FX_RAM_BANKS - 1);
244 GSU.vCacheBaseReg = (uint32) p[GSU_CBR];
245 GSU.vCacheBaseReg |= ((uint32) p[GSU_CBR + 1]) << 8;
246
247 // Update status register variables
248 GSU.vZero = !(GSU.vStatusReg & FLG_Z);
249 GSU.vSign = (GSU.vStatusReg & FLG_S) << 12;
250 GSU.vOverflow = (GSU.vStatusReg & FLG_OV) << 16;
251 GSU.vCarry = (GSU.vStatusReg & FLG_CY) >> 2;
252
253 // Set bank pointers
254 GSU.pvRamBank = GSU.apvRamBank[GSU.vRamBankReg & 0x3];
255 GSU.pvRomBank = GSU.apvRomBank[GSU.vRomBankReg];
256 GSU.pvPrgBank = GSU.apvRomBank[GSU.vPrgBankReg];
257
258 // Set screen pointers
259 GSU.pvScreenBase = &GSU.pvRam[USEX8(p[GSU_SCBR]) << 10];
260 n = (int) (!!(p[GSU_SCMR] & 0x04));
261 n |= ((int) (!!(p[GSU_SCMR] & 0x20))) << 1;
262 GSU.vScreenHeight = GSU.vScreenRealHeight = avHeight[n];
263 GSU.vMode = p[GSU_SCMR] & 0x03;
264
265 if (n == 3)
266 GSU.vScreenSize = (256 / 8) * (256 / 8) * 32;
267 else
268 GSU.vScreenSize = (GSU.vScreenHeight / 8) * (256 / 8) * avMult[GSU.vMode];
269
270 if (GSU.vPlotOptionReg & 0x10) // OBJ Mode (for drawing into sprites)
271 GSU.vScreenHeight = 256;
272
273 if (GSU.pvScreenBase + GSU.vScreenSize > GSU.pvRam + (GSU.nRamBanks * 65536))
274 GSU.pvScreenBase = GSU.pvRam + (GSU.nRamBanks * 65536) - GSU.vScreenSize;
275
276 GSU.pfPlot = fx_PlotTable[GSU.vMode];
277 GSU.pfRpix = fx_PlotTable[GSU.vMode + 5];
278
279 fx_OpcodeTable[0x04c] = GSU.pfPlot;
280 fx_OpcodeTable[0x14c] = GSU.pfRpix;
281 fx_OpcodeTable[0x24c] = GSU.pfPlot;
282 fx_OpcodeTable[0x34c] = GSU.pfRpix;
283
284 fx_computeScreenPointers();
285
286 //fx_backupCache();
287}
288
289static void fx_writeRegisterSpace (void)
290{
291 uint8 *p;
292
293 p = GSU.pvRegisters;
294 for (int i = 0; i < 16; i++)
295 {
296 *p++ = (uint8) GSU.avReg[i];
297 *p++ = (uint8) (GSU.avReg[i] >> 8);
298 }
299
300 // Update status register
301 if (USEX16(GSU.vZero) == 0)
302 SF(Z);
303 else
304 CF(Z);
305
306 if (GSU.vSign & 0x8000)
307 SF(S);
308 else
309 CF(S);
310
311 if (GSU.vOverflow >= 0x8000 || GSU.vOverflow < -0x8000)
312 SF(OV);
313 else
314 CF(OV);
315
316 if (GSU.vCarry)
317 SF(CY);
318 else
319 CF(CY);
320
321 p = GSU.pvRegisters;
322 p[GSU_SFR] = (uint8) GSU.vStatusReg;
323 p[GSU_SFR + 1] = (uint8) (GSU.vStatusReg >> 8);
324 p[GSU_PBR] = (uint8) GSU.vPrgBankReg;
325 p[GSU_ROMBR] = (uint8) GSU.vRomBankReg;
326 p[GSU_RAMBR] = (uint8) GSU.vRamBankReg;
327 p[GSU_CBR] = (uint8) GSU.vCacheBaseReg;
328 p[GSU_CBR + 1] = (uint8) (GSU.vCacheBaseReg >> 8);
329
330 //fx_restoreCache();
331}
332
333// Update RamBankReg and RAM Bank pointer
334static void fx_updateRamBank (uint8 byte)
335{
336 // Update BankReg and Bank pointer
337 GSU.vRamBankReg = (uint32) byte & (FX_RAM_BANKS - 1);
338 GSU.pvRamBank = GSU.apvRamBank[byte & 0x3];
339}
340
341// SCBR write seen. We need to update our cached screen pointers
342static void fx_dirtySCBR (void)
343{
344 GSU.vSCBRDirty = TRUE;
345}
346
347static bool8 fx_checkStartAddress (void)
348{
349 // Check if we start inside the cache
350 if (GSU.bCacheActive && R15 >= GSU.vCacheBaseReg && R15 < (GSU.vCacheBaseReg + 512))
351 return (TRUE);
352
353 /*
354 // Check if we're in an unused area
355 if (GSU.vPrgBankReg < 0x40 && R15 < 0x8000)
356 return (FALSE);
357 */
358
359 if (GSU.vPrgBankReg >= 0x60 && GSU.vPrgBankReg <= 0x6f)
360 return (FALSE);
361
362 if (GSU.vPrgBankReg >= 0x74)
363 return (FALSE);
364
365 // Check if we're in RAM and the RAN flag is not set
366 if (GSU.vPrgBankReg >= 0x70 && GSU.vPrgBankReg <= 0x73 && !(SCMR & (1 << 3)))
367 return (FALSE);
368
369 // If not, we're in ROM, so check if the RON flag is set
370 if (!(SCMR & (1 << 4)))
371 return (FALSE);
372
373 return (TRUE);
374}
375
376// Execute until the next stop instruction
377static uint32 FxEmulate (uint32 nInstructions)
378{
379 uint32 vCount;
380
381 // Read registers and initialize GSU session
382 fx_readRegisterSpace();
383
384 // Check if the start address is valid
385 if (!fx_checkStartAddress())
386 {
387 CF(G);
388 fx_writeRegisterSpace();
389 /*
390 GSU.vIllegalAddress = (GSU.vPrgBankReg << 24) | R15;
391 return (FX_ERROR_ILLEGAL_ADDRESS);
392 */
393
394 return (0);
395 }
396
397 // Execute GSU session
398 CF(IRQ);
399
400 /*
401 if (GSU.bBreakPoint)
402 vCount = fx_run_to_breakpoint(nInstructions);
403 else
404 */
405 vCount = fx_run(nInstructions);
406
407 // Store GSU registers
408 fx_writeRegisterSpace();
409
410 // Check for error code
411 if (GSU.vErrorCode)
412 return (GSU.vErrorCode);
413 else
414 return (vCount);
415}
416
417void fx_computeScreenPointers (void)
418{
419 if (GSU.vMode != GSU.vPrevMode || GSU.vPrevScreenHeight != GSU.vScreenHeight || GSU.vSCBRDirty)
420 {
421 GSU.vSCBRDirty = FALSE;
422
423 // Make a list of pointers to the start of each screen column
424 switch (GSU.vScreenHeight)
425 {
426 case 128:
427 switch (GSU.vMode)
428 {
429 case 0:
430 for (int i = 0; i < 32; i++)
431 {
432 GSU.apvScreen[i] = GSU.pvScreenBase + (i << 4);
433 GSU.x[i] = i << 8;
434 }
435
436 break;
437
438 case 1:
439 for (int i = 0; i < 32; i++)
440 {
441 GSU.apvScreen[i] = GSU.pvScreenBase + (i << 5);
442 GSU.x[i] = i << 9;
443 }
444
445 break;
446
447 case 2:
448 case 3:
449 for (int i = 0; i < 32; i++)
450 {
451 GSU.apvScreen[i] = GSU.pvScreenBase + (i << 6);
452 GSU.x[i] = i << 10;
453 }
454
455 break;
456 }
457
458 break;
459
460 case 160:
461 switch (GSU.vMode)
462 {
463 case 0:
464 for (int i = 0; i < 32; i++)
465 {
466 GSU.apvScreen[i] = GSU.pvScreenBase + (i << 4);
467 GSU.x[i] = (i << 8) + (i << 6);
468 }
469
470 break;
471
472 case 1:
473 for (int i = 0; i < 32; i++)
474 {
475 GSU.apvScreen[i] = GSU.pvScreenBase + (i << 5);
476 GSU.x[i] = (i << 9) + (i << 7);
477 }
478
479 break;
480
481 case 2:
482 case 3:
483 for (int i = 0; i < 32; i++)
484 {
485 GSU.apvScreen[i] = GSU.pvScreenBase + (i << 6);
486 GSU.x[i] = (i << 10) + (i << 8);
487 }
488
489 break;
490 }
491
492 break;
493
494 case 192:
495 switch (GSU.vMode)
496 {
497 case 0:
498 for (int i = 0; i < 32; i++)
499 {
500 GSU.apvScreen[i] = GSU.pvScreenBase + (i << 4);
501 GSU.x[i] = (i << 8) + (i << 7);
502 }
503
504 break;
505
506 case 1:
507 for (int i = 0; i < 32; i++)
508 {
509 GSU.apvScreen[i] = GSU.pvScreenBase + (i << 5);
510 GSU.x[i] = (i << 9) + (i << 8);
511 }
512
513 break;
514
515 case 2:
516 case 3:
517 for (int i = 0; i < 32; i++)
518 {
519 GSU.apvScreen[i] = GSU.pvScreenBase + (i << 6);
520 GSU.x[i] = (i << 10) + (i << 9);
521 }
522
523 break;
524 }
525
526 break;
527
528 case 256:
529 switch (GSU.vMode)
530 {
531 case 0:
532 for (int i = 0; i < 32; i++)
533 {
534 GSU.apvScreen[i] = GSU.pvScreenBase + ((i & 0x10) << 9) + ((i & 0xf) << 8);
535 GSU.x[i] = ((i & 0x10) << 8) + ((i & 0xf) << 4);
536 }
537
538 break;
539
540 case 1:
541 for (int i = 0; i < 32; i++)
542 {
543 GSU.apvScreen[i] = GSU.pvScreenBase + ((i & 0x10) << 10) + ((i & 0xf) << 9);
544 GSU.x[i] = ((i & 0x10) << 9) + ((i & 0xf) << 5);
545 }
546
547 break;
548
549 case 2:
550 case 3:
551 for (int i = 0; i < 32; i++)
552 {
553 GSU.apvScreen[i] = GSU.pvScreenBase + ((i & 0x10) << 11) + ((i & 0xf) << 10);
554 GSU.x[i] = ((i & 0x10) << 10) + ((i & 0xf) << 6);
555 }
556
557 break;
558 }
559
560 break;
561 }
562
563 GSU.vPrevMode = GSU.vMode;
564 GSU.vPrevScreenHeight = GSU.vScreenHeight;
565 }
566}
567
568// Write access to the cache
569static void FxCacheWriteAccess (uint16 vAddress)
570{
571 /*
572 if (!GSU.bCacheActive)
573 {
574 uint8 v = GSU.pvCache[GSU.pvCache[vAddress & 0x1ff];
575 fx_setCache();
576 GSU.pvCache[GSU.pvCache[vAddress & 0x1ff] = v;
577 }
578 */
579
580 if ((vAddress & 0x00f) == 0x00f)
581 GSU.vCacheFlags |= 1 << ((vAddress & 0x1f0) >> 4);
582}
583
584static void FxFlushCache (void)
585{
586 GSU.vCacheFlags = 0;
587 GSU.vCacheBaseReg = 0;
588 GSU.bCacheActive = FALSE;
589 //GSU.vPipe = 0x1;
590}
591
592void fx_flushCache (void)
593{
594 //fx_restoreCache();
595 GSU.vCacheFlags = 0;
596 GSU.bCacheActive = FALSE;
597}
598
599/*
600static void fx_setCache (void)
601{
602 uint32 c;
603
604 GSU.bCacheActive = TRUE;
605 GSU.pvRegisters[0x3e] &= 0xf0;
606
607 c = (uint32) GSU.pvRegisters[0x3e];
608 c |= ((uint32) GSU.pvRegisters[0x3f]) << 8;
609 if (c == GSU.vCacheBaseReg)
610 return;
611
612 GSU.vCacheBaseReg = c;
613 GSU.vCacheFlags = 0;
614
615 if (c < (0x10000 - 512))
616 {
617 const uint8 *t = &ROM(c);
618 memcpy(GSU.pvCache, t, 512);
619 }
620 else
621 {
622 const uint8 *t1, *t2;
623 uint32 i = 0x10000 - c;
624
625 t1 = &ROM(c);
626 t2 = &ROM(0);
627 memcpy(GSU.pvCache, t1, i);
628 memcpy(&GSU.pvCache[i], t2, 512 - i);
629 }
630}
631*/
632
633/*
634static void fx_backupCache (void)
635{
636 uint32 v = GSU.vCacheFlags;
637 uint32 c = USEX16(GSU.vCacheBaseReg);
638
639 if (v)
640 {
641 for (int i = 0; i < 32; i++)
642 {
643 if (v & 1)
644 {
645 if (c < (0x10000 - 16))
646 {
647 uint8 *t = &GSU.pvPrgBank[c];
648 memcpy(&GSU.avCacheBackup[i << 4], t, 16);
649 memcpy(t, &GSU.pvCache[i << 4], 16);
650 }
651 else
652 {
653 uint8 *t1, *t2;
654 uint32 a = 0x10000 - c;
655
656 t1 = &GSU.pvPrgBank[c];
657 t2 = &GSU.pvPrgBank[0];
658 memcpy(&GSU.avCacheBackup[i << 4], t1, a);
659 memcpy(t1, &GSU.pvCache[i << 4], a);
660 memcpy(&GSU.avCacheBackup[(i << 4) + a], t2, 16 - a);
661 memcpy(t2, &GSU.pvCache[(i << 4) + a], 16 - a);
662 }
663 }
664
665 c = USEX16(c + 16);
666 v >>= 1;
667 }
668 }
669}
670*/
671
672/*
673static void fx_restoreCache()
674{
675 uint32 v = GSU.vCacheFlags;
676 uint32 c = USEX16(GSU.vCacheBaseReg);
677
678 if (v)
679 {
680 for (int i = 0; i < 32; i++)
681 {
682 if (v & 1)
683 {
684 if (c < (0x10000 - 16))
685 {
686 uint8 *t = &GSU.pvPrgBank[c];
687 memcpy(t, &GSU.avCacheBackup[i << 4], 16);
688 memcpy(&GSU.pvCache[i << 4], t, 16);
689 }
690 else
691 {
692 uint8 *t1, *t2;
693 uint32 a = 0x10000 - c;
694
695 t1 = &GSU.pvPrgBank[c];
696 t2 = &GSU.pvPrgBank[0];
697 memcpy(t1, &GSU.avCacheBackup[i << 4], a);
698 memcpy(&GSU.pvCache[i << 4], t1, a);
699 memcpy(t2, &GSU.avCacheBackup[(i << 4) + a], 16 - a);
700 memcpy(&GSU.pvCache[(i << 4) + a], t2, 16 - a);
701 }
702 }
703
704 c = USEX16(c + 16);
705 v >>= 1;
706 }
707 }
708}
709*/
710
711// Breakpoints
712/*
713static void FxBreakPointSet (uint32 vAddress)
714{
715 GSU.bBreakPoint = TRUE;
716 GSU.vBreakPoint = USEX16(vAddress);
717}
718*/
719
720/*
721static void FxBreakPointClear (void)
722{
723 GSU.bBreakPoint = FALSE;
724}
725*/
726
727// Step by step execution
728/*
729static uint32 FxStepOver (uint32 nInstructions)
730{
731 uint32 vCount;
732
733 fx_readRegisterSpace();
734
735 if (!fx_checkStartAddress())
736 {
737 CF(G);
738 #if 0
739 GSU.vIllegalAddress = (GSU.vPrgBankReg << 24) | R15;
740 return (FX_ERROR_ILLEGAL_ADDRESS);
741 #else
742 return (0);
743 #endif
744 }
745
746 if (PIPE >= 0xf0)
747 GSU.vStepPoint = USEX16(R15 + 3);
748 else
749 if ((PIPE >= 0x05 && PIPE <= 0x0f) || (PIPE >= 0xa0 && PIPE <= 0xaf))
750 GSU.vStepPoint = USEX16(R15 + 2);
751 else
752 GSU.vStepPoint = USEX16(R15 + 1);
753
754 vCount = fx_step_over(nInstructions);
755
756 fx_writeRegisterSpace();
757
758 if (GSU.vErrorCode)
759 return (GSU.vErrorCode);
760 else
761 return (vCount);
762}
763*/
764
765// Errors
766/*
767static int FxGetErrorCode (void)
768{
769 return (GSU.vErrorCode);
770}
771*/
772
773/*
774static int FxGetIllegalAddress (void)
775{
776 return (GSU.vIllegalAddress);
777}
778*/
779
780// Access to internal registers
781/*
782static uint32 FxGetColorRegister (void)
783{
784 return (GSU.vColorReg & 0xff);
785}
786*/
787
788/*
789static uint32 FxGetPlotOptionRegister (void)
790{
791 return (GSU.vPlotOptionReg & 0x1f);
792}
793*/
794
795/*
796static uint32 FxGetSourceRegisterIndex (void)
797{
798 return (GSU.pvSreg - GSU.avReg);
799}
800*/
801
802/*
803static uint32 FxGetDestinationRegisterIndex (void)
804{
805 return (GSU.pvDreg - GSU.avReg);
806}
807*/
808
809// Get the byte currently in the pipe
810/*
811static uint8 FxPipe (void)
812{
813 return (GSU.vPipe);
814}
815*/
816