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 | |
12 | static void FxReset (struct FxInfo_s *); |
13 | static void fx_readRegisterSpace (void); |
14 | static void fx_writeRegisterSpace (void); |
15 | static void fx_updateRamBank (uint8); |
16 | static void fx_dirtySCBR (void); |
17 | static bool8 fx_checkStartAddress (void); |
18 | static uint32 FxEmulate (uint32); |
19 | static void FxCacheWriteAccess (uint16); |
20 | static void FxFlushCache (void); |
21 | |
22 | |
23 | void S9xInitSuperFX (void) |
24 | { |
25 | memset((uint8 *) &GSU, 0, sizeof(struct FxRegs_s)); |
26 | } |
27 | |
28 | void 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 | |
39 | void 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 | |
128 | uint8 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 | |
143 | void 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 | |
155 | static 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 | |
219 | static 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 | |
289 | static 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 |
334 | static 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 |
342 | static void fx_dirtySCBR (void) |
343 | { |
344 | GSU.vSCBRDirty = TRUE; |
345 | } |
346 | |
347 | static 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 |
377 | static 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 | |
417 | void 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 |
569 | static 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 | |
584 | static void FxFlushCache (void) |
585 | { |
586 | GSU.vCacheFlags = 0; |
587 | GSU.vCacheBaseReg = 0; |
588 | GSU.bCacheActive = FALSE; |
589 | //GSU.vPipe = 0x1; |
590 | } |
591 | |
592 | void fx_flushCache (void) |
593 | { |
594 | //fx_restoreCache(); |
595 | GSU.vCacheFlags = 0; |
596 | GSU.bCacheActive = FALSE; |
597 | } |
598 | |
599 | /* |
600 | static 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 | /* |
634 | static 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 | /* |
673 | static 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 | /* |
713 | static void FxBreakPointSet (uint32 vAddress) |
714 | { |
715 | GSU.bBreakPoint = TRUE; |
716 | GSU.vBreakPoint = USEX16(vAddress); |
717 | } |
718 | */ |
719 | |
720 | /* |
721 | static void FxBreakPointClear (void) |
722 | { |
723 | GSU.bBreakPoint = FALSE; |
724 | } |
725 | */ |
726 | |
727 | // Step by step execution |
728 | /* |
729 | static 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 | /* |
767 | static int FxGetErrorCode (void) |
768 | { |
769 | return (GSU.vErrorCode); |
770 | } |
771 | */ |
772 | |
773 | /* |
774 | static int FxGetIllegalAddress (void) |
775 | { |
776 | return (GSU.vIllegalAddress); |
777 | } |
778 | */ |
779 | |
780 | // Access to internal registers |
781 | /* |
782 | static uint32 FxGetColorRegister (void) |
783 | { |
784 | return (GSU.vColorReg & 0xff); |
785 | } |
786 | */ |
787 | |
788 | /* |
789 | static uint32 FxGetPlotOptionRegister (void) |
790 | { |
791 | return (GSU.vPlotOptionReg & 0x1f); |
792 | } |
793 | */ |
794 | |
795 | /* |
796 | static uint32 FxGetSourceRegisterIndex (void) |
797 | { |
798 | return (GSU.pvSreg - GSU.avReg); |
799 | } |
800 | */ |
801 | |
802 | /* |
803 | static uint32 FxGetDestinationRegisterIndex (void) |
804 | { |
805 | return (GSU.pvDreg - GSU.avReg); |
806 | } |
807 | */ |
808 | |
809 | // Get the byte currently in the pipe |
810 | /* |
811 | static uint8 FxPipe (void) |
812 | { |
813 | return (GSU.vPipe); |
814 | } |
815 | */ |
816 | |