* [2SF] Used more up-to-date asmjit, despite the ugly looking code.
| ... | ... |
@@ -180,12 +180,6 @@ |
| 180 | 180 |
#include "cpuops.h" |
| 181 | 181 |
#include "dma.h" |
| 182 | 182 |
#include "apu/apu.h" |
| 183 |
-//#include "fxemu.h" |
|
| 184 |
-//#include "snapshot.h" |
|
| 185 |
-#ifdef DEBUGGER |
|
| 186 |
-#include "debug.h" |
|
| 187 |
-#include "missing.h" |
|
| 188 |
-#endif |
|
| 189 | 183 |
|
| 190 | 184 |
static inline void S9xReschedule() |
| 191 | 185 |
{
|
| ... | ... |
@@ -193,33 +187,32 @@ static inline void S9xReschedule() |
| 193 | 187 |
{
|
| 194 | 188 |
case HC_HBLANK_START_EVENT: |
| 195 | 189 |
CPU.WhichEvent = HC_HDMA_START_EVENT; |
| 196 |
- CPU.NextEvent = Timings.HDMAStart; |
|
| 190 |
+ CPU.NextEvent = Timings.HDMAStart; |
|
| 197 | 191 |
break; |
| 198 | 192 |
|
| 199 | 193 |
case HC_HDMA_START_EVENT: |
| 200 | 194 |
CPU.WhichEvent = HC_HCOUNTER_MAX_EVENT; |
| 201 |
- CPU.NextEvent = Timings.H_Max; |
|
| 195 |
+ CPU.NextEvent = Timings.H_Max; |
|
| 202 | 196 |
break; |
| 203 | 197 |
|
| 204 | 198 |
case HC_HCOUNTER_MAX_EVENT: |
| 205 | 199 |
CPU.WhichEvent = HC_HDMA_INIT_EVENT; |
| 206 |
- CPU.NextEvent = Timings.HDMAInit; |
|
| 200 |
+ CPU.NextEvent = Timings.HDMAInit; |
|
| 207 | 201 |
break; |
| 208 | 202 |
|
| 209 | 203 |
case HC_HDMA_INIT_EVENT: |
| 210 | 204 |
CPU.WhichEvent = HC_RENDER_EVENT; |
| 211 |
- CPU.NextEvent = Timings.RenderPos; |
|
| 205 |
+ CPU.NextEvent = Timings.RenderPos; |
|
| 212 | 206 |
break; |
| 213 | 207 |
|
| 214 | 208 |
case HC_RENDER_EVENT: |
| 215 | 209 |
CPU.WhichEvent = HC_WRAM_REFRESH_EVENT; |
| 216 |
- CPU.NextEvent = Timings.WRAMRefreshPos; |
|
| 210 |
+ CPU.NextEvent = Timings.WRAMRefreshPos; |
|
| 217 | 211 |
break; |
| 218 | 212 |
|
| 219 | 213 |
case HC_WRAM_REFRESH_EVENT: |
| 220 | 214 |
CPU.WhichEvent = HC_HBLANK_START_EVENT; |
| 221 |
- CPU.NextEvent = Timings.HBlankStart; |
|
| 222 |
- break; |
|
| 215 |
+ CPU.NextEvent = Timings.HBlankStart; |
|
| 223 | 216 |
} |
| 224 | 217 |
} |
| 225 | 218 |
|
| ... | ... |
@@ -236,23 +229,23 @@ void S9xMainLoop() |
| 236 | 229 |
if (CPU.WaitingForInterrupt) |
| 237 | 230 |
{
|
| 238 | 231 |
CPU.WaitingForInterrupt = false; |
| 239 |
- Registers.PCw++; |
|
| 232 |
+ ++Registers.PC.W.xPC; |
|
| 240 | 233 |
} |
| 241 | 234 |
|
| 242 | 235 |
S9xOpcode_NMI(); |
| 243 | 236 |
} |
| 244 | 237 |
} |
| 245 | 238 |
|
| 246 |
- if (CPU.IRQTransition || CPU.IRQExternal) |
|
| 239 |
+ if (CPU.IRQTransition) |
|
| 247 | 240 |
{
|
| 248 | 241 |
if (CPU.IRQPending) |
| 249 |
- CPU.IRQPending--; |
|
| 242 |
+ --CPU.IRQPending; |
|
| 250 | 243 |
else |
| 251 | 244 |
{
|
| 252 | 245 |
if (CPU.WaitingForInterrupt) |
| 253 | 246 |
{
|
| 254 | 247 |
CPU.WaitingForInterrupt = false; |
| 255 |
- Registers.PCw++; |
|
| 248 |
+ ++Registers.PC.W.xPC; |
|
| 256 | 249 |
} |
| 257 | 250 |
|
| 258 | 251 |
CPU.IRQTransition = false; |
| ... | ... |
@@ -263,45 +256,15 @@ void S9xMainLoop() |
| 263 | 256 |
} |
| 264 | 257 |
} |
| 265 | 258 |
|
| 266 |
- #ifdef DEBUGGER |
|
| 267 |
- if ((CPU.Flags & BREAK_FLAG) && !(CPU.Flags & SINGLE_STEP_FLAG)) |
|
| 268 |
- {
|
|
| 269 |
- for (int Break = 0; Break != 6; Break++) |
|
| 270 |
- {
|
|
| 271 |
- if (S9xBreakpoint[Break].Enabled && |
|
| 272 |
- S9xBreakpoint[Break].Bank == Registers.PB && |
|
| 273 |
- S9xBreakpoint[Break].Address == Registers.PCw) |
|
| 274 |
- {
|
|
| 275 |
- if (S9xBreakpoint[Break].Enabled == 2) |
|
| 276 |
- S9xBreakpoint[Break].Enabled = true; |
|
| 277 |
- else |
|
| 278 |
- CPU.Flags |= DEBUG_MODE_FLAG; |
|
| 279 |
- } |
|
| 280 |
- } |
|
| 281 |
- } |
|
| 282 |
- |
|
| 283 |
- if (CPU.Flags & DEBUG_MODE_FLAG) |
|
| 284 |
- break; |
|
| 285 |
- |
|
| 286 |
- if (CPU.Flags & TRACE_FLAG) |
|
| 287 |
- S9xTrace(); |
|
| 288 |
- |
|
| 289 |
- if (CPU.Flags & SINGLE_STEP_FLAG) |
|
| 290 |
- {
|
|
| 291 |
- CPU.Flags &= ~SINGLE_STEP_FLAG; |
|
| 292 |
- CPU.Flags |= DEBUG_MODE_FLAG; |
|
| 293 |
- } |
|
| 294 |
- #endif |
|
| 295 |
- |
|
| 296 | 259 |
if (CPU.Flags & SCAN_KEYS_FLAG) |
| 297 | 260 |
break; |
| 298 | 261 |
|
| 299 |
- register uint8_t Op; |
|
| 300 |
- register struct SOpcodes *Opcodes; |
|
| 262 |
+ register uint8_t Op; |
|
| 263 |
+ register SOpcodes *Opcodes; |
|
| 301 | 264 |
|
| 302 | 265 |
if (CPU.PCBase) |
| 303 | 266 |
{
|
| 304 |
- Op = CPU.PCBase[Registers.PCw]; |
|
| 267 |
+ Op = CPU.PCBase[Registers.PC.W.xPC]; |
|
| 305 | 268 |
CPU.PrevCycles = CPU.Cycles; |
| 306 | 269 |
CPU.Cycles += CPU.MemSpeed; |
| 307 | 270 |
S9xCheckInterrupts(); |
| ... | ... |
@@ -309,60 +272,32 @@ void S9xMainLoop() |
| 309 | 272 |
} |
| 310 | 273 |
else |
| 311 | 274 |
{
|
| 312 |
- Op = S9xGetByte(Registers.PBPC); |
|
| 275 |
+ Op = S9xGetByte(Registers.PC.xPBPC); |
|
| 313 | 276 |
OpenBus = Op; |
| 314 | 277 |
Opcodes = S9xOpcodesSlow; |
| 315 | 278 |
} |
| 316 | 279 |
|
| 317 |
- if ((Registers.PCw & MEMMAP_MASK) + ICPU.S9xOpLengths[Op] >= MEMMAP_BLOCK_SIZE) |
|
| 280 |
+ if ((Registers.PC.W.xPC & MEMMAP_MASK) + ICPU.S9xOpLengths[Op] >= MEMMAP_BLOCK_SIZE) |
|
| 318 | 281 |
{
|
| 319 |
- uint8_t *oldPCBase = CPU.PCBase; |
|
| 282 |
+ uint8_t *oldPCBase = CPU.PCBase; |
|
| 320 | 283 |
|
| 321 |
- CPU.PCBase = S9xGetBasePointer(ICPU.ShiftedPB + ((uint16_t) (Registers.PCw + 4))); |
|
| 322 |
- if (oldPCBase != CPU.PCBase || (Registers.PCw & ~MEMMAP_MASK) == (0xffff & ~MEMMAP_MASK)) |
|
| 284 |
+ CPU.PCBase = S9xGetBasePointer(ICPU.ShiftedPB + (static_cast<uint16_t>(Registers.PC.W.xPC + 4))); |
|
| 285 |
+ if (oldPCBase != CPU.PCBase || (Registers.PC.W.xPC & ~MEMMAP_MASK) == (0xffff & ~MEMMAP_MASK)) |
|
| 323 | 286 |
Opcodes = S9xOpcodesSlow; |
| 324 | 287 |
} |
| 325 | 288 |
|
| 326 |
- Registers.PCw++; |
|
| 289 |
+ ++Registers.PC.W.xPC; |
|
| 327 | 290 |
(*Opcodes[Op].S9xOpcode)(); |
| 328 |
- |
|
| 329 |
- /*if (Settings.SA1) |
|
| 330 |
- S9xSA1MainLoop();*/ |
|
| 331 | 291 |
} |
| 332 | 292 |
|
| 333 | 293 |
S9xPackStatus(); |
| 334 | 294 |
|
| 335 | 295 |
if (CPU.Flags & SCAN_KEYS_FLAG) |
| 336 |
- {
|
|
| 337 |
- /*#ifdef DEBUGGER |
|
| 338 |
- if (!(CPU.Flags & FRAME_ADVANCE_FLAG)) |
|
| 339 |
- #endif |
|
| 340 |
- S9xSyncSpeed();*/ |
|
| 341 | 296 |
CPU.Flags &= ~SCAN_KEYS_FLAG; |
| 342 |
- } |
|
| 343 | 297 |
} |
| 344 | 298 |
|
| 345 | 299 |
void S9xDoHEventProcessing() |
| 346 | 300 |
{
|
| 347 |
-#ifdef DEBUGGER |
|
| 348 |
- static char eventname[7][32] = |
|
| 349 |
- {
|
|
| 350 |
- "", |
|
| 351 |
- "HC_HBLANK_START_EVENT", |
|
| 352 |
- "HC_HDMA_START_EVENT ", |
|
| 353 |
- "HC_HCOUNTER_MAX_EVENT", |
|
| 354 |
- "HC_HDMA_INIT_EVENT ", |
|
| 355 |
- "HC_RENDER_EVENT ", |
|
| 356 |
- "HC_WRAM_REFRESH_EVENT" |
|
| 357 |
- }; |
|
| 358 |
-#endif |
|
| 359 |
- |
|
| 360 |
-#ifdef DEBUGGER |
|
| 361 |
- if (Settings.TraceHCEvent) |
|
| 362 |
- S9xTraceFormattedMessage("--- HC event processing (%s) expected HC:%04d executed HC:%04d",
|
|
| 363 |
- eventname[CPU.WhichEvent], CPU.NextEvent, CPU.Cycles); |
|
| 364 |
-#endif |
|
| 365 |
- |
|
| 366 | 301 |
switch (CPU.WhichEvent) |
| 367 | 302 |
{
|
| 368 | 303 |
case HC_HBLANK_START_EVENT: |
| ... | ... |
@@ -373,23 +308,11 @@ void S9xDoHEventProcessing() |
| 373 | 308 |
S9xReschedule(); |
| 374 | 309 |
|
| 375 | 310 |
if (PPU.HDMA && CPU.V_Counter <= PPU.ScreenHeight) |
| 376 |
- {
|
|
| 377 |
- #ifdef DEBUGGER |
|
| 378 |
- S9xTraceFormattedMessage("*** HDMA Transfer HC:%04d, Channel:%02x", CPU.Cycles, PPU.HDMA);
|
|
| 379 |
- #endif |
|
| 380 | 311 |
PPU.HDMA = S9xDoHDMA(PPU.HDMA); |
| 381 |
- } |
|
| 382 | 312 |
|
| 383 | 313 |
break; |
| 384 | 314 |
|
| 385 | 315 |
case HC_HCOUNTER_MAX_EVENT: |
| 386 |
- /*if (Settings.SuperFX) |
|
| 387 |
- {
|
|
| 388 |
- if (!SuperFX.oneLineDone) |
|
| 389 |
- S9xSuperFXExec(); |
|
| 390 |
- SuperFX.oneLineDone = false; |
|
| 391 |
- }*/ |
|
| 392 |
- |
|
| 393 | 316 |
S9xAPUEndScanline(); |
| 394 | 317 |
CPU.Cycles -= Timings.H_Max; |
| 395 | 318 |
CPU.PrevCycles -= Timings.H_Max; |
| ... | ... |
@@ -398,11 +321,11 @@ void S9xDoHEventProcessing() |
| 398 | 321 |
if ((Timings.NMITriggerPos != 0xffff) && (Timings.NMITriggerPos >= Timings.H_Max)) |
| 399 | 322 |
Timings.NMITriggerPos -= Timings.H_Max; |
| 400 | 323 |
|
| 401 |
- CPU.V_Counter++; |
|
| 402 |
- if (CPU.V_Counter >= Timings.V_Max) // V ranges from 0 to Timings.V_Max - 1 |
|
| 324 |
+ ++CPU.V_Counter; |
|
| 325 |
+ if (CPU.V_Counter >= Timings.V_Max) // V ranges from 0 to Timings.V_Max - 1 |
|
| 403 | 326 |
{
|
| 404 | 327 |
CPU.V_Counter = 0; |
| 405 |
- Timings.InterlaceField ^= 1; |
|
| 328 |
+ Timings.InterlaceField = !Timings.InterlaceField; |
|
| 406 | 329 |
|
| 407 | 330 |
// From byuu: |
| 408 | 331 |
// [NTSC] |
| ... | ... |
@@ -412,20 +335,17 @@ void S9xDoHEventProcessing() |
| 412 | 335 |
// interlace mode has 625 scanlines: 313 on the even frame, and 312 on the odd. |
| 413 | 336 |
// non-interlace mode has 624 scanlines: 312 scanlines on both even and odd frames. |
| 414 | 337 |
if (IPPU.Interlace && !Timings.InterlaceField) |
| 415 |
- Timings.V_Max = Timings.V_Max_Master + 1; // 263 (NTSC), 313?(PAL) |
|
| 338 |
+ Timings.V_Max = Timings.V_Max_Master + 1; // 263 (NTSC), 313?(PAL) |
|
| 416 | 339 |
else |
| 417 |
- Timings.V_Max = Timings.V_Max_Master; // 262 (NTSC), 312?(PAL) |
|
| 340 |
+ Timings.V_Max = Timings.V_Max_Master; // 262 (NTSC), 312?(PAL) |
|
| 418 | 341 |
|
| 419 | 342 |
Memory.FillRAM[0x213F] ^= 0x80; |
| 420 |
- PPU.RangeTimeOver = 0; |
|
| 421 | 343 |
|
| 422 | 344 |
// FIXME: reading $4210 will wait 2 cycles, then perform reading, then wait 4 more cycles. |
| 423 | 345 |
Memory.FillRAM[0x4210] = Model->_5A22; |
| 424 | 346 |
CPU.NMILine = false; |
| 425 | 347 |
Timings.NMITriggerPos = 0xffff; |
| 426 | 348 |
|
| 427 |
- ICPU.Frame++; |
|
| 428 |
- PPU.HVBeamCounterLatched = 0; |
|
| 429 | 349 |
CPU.Flags |= SCAN_KEYS_FLAG; |
| 430 | 350 |
} |
| 431 | 351 |
|
| ... | ... |
@@ -435,48 +355,40 @@ void S9xDoHEventProcessing() |
| 435 | 355 |
// In interlace mode, there are always 341 dots per scanline. Even frames have 263 scanlines, |
| 436 | 356 |
// and odd frames have 262 scanlines. |
| 437 | 357 |
// Interlace mode scanline 240 on odd frames is not missing a dot. |
| 438 |
- if (CPU.V_Counter == 240 && !IPPU.Interlace && Timings.InterlaceField) // V=240 |
|
| 439 |
- Timings.H_Max = Timings.H_Max_Master - ONE_DOT_CYCLE; // HC=1360 |
|
| 358 |
+ if (CPU.V_Counter == 240 && !IPPU.Interlace && Timings.InterlaceField) // V=240 |
|
| 359 |
+ Timings.H_Max = Timings.H_Max_Master - ONE_DOT_CYCLE; // HC=1360 |
|
| 440 | 360 |
else |
| 441 |
- Timings.H_Max = Timings.H_Max_Master; // HC=1364 |
|
| 361 |
+ Timings.H_Max = Timings.H_Max_Master; // HC=1364 |
|
| 442 | 362 |
|
| 443 | 363 |
if (Model->_5A22 == 2) |
| 444 | 364 |
{
|
| 445 | 365 |
if (CPU.V_Counter != 240 || IPPU.Interlace || !Timings.InterlaceField) // V=240 |
| 446 | 366 |
{
|
| 447 |
- if (Timings.WRAMRefreshPos == SNES_WRAM_REFRESH_HC_v2 - ONE_DOT_CYCLE) // HC=534 |
|
| 448 |
- Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2; // HC=538 |
|
| 367 |
+ if (Timings.WRAMRefreshPos == SNES_WRAM_REFRESH_HC_v2 - ONE_DOT_CYCLE) // HC=534 |
|
| 368 |
+ Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2; // HC=538 |
|
| 449 | 369 |
else |
| 450 |
- Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2 - ONE_DOT_CYCLE; // HC=534 |
|
| 370 |
+ Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2 - ONE_DOT_CYCLE; // HC=534 |
|
| 451 | 371 |
} |
| 452 | 372 |
} |
| 453 | 373 |
else |
| 454 | 374 |
Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v1; |
| 455 | 375 |
|
| 456 |
- if (CPU.V_Counter == PPU.ScreenHeight + FIRST_VISIBLE_LINE) // VBlank starts from V=225(240). |
|
| 376 |
+ if (CPU.V_Counter == PPU.ScreenHeight + FIRST_VISIBLE_LINE) // VBlank starts from V=225(240). |
|
| 457 | 377 |
{
|
| 458 |
- //S9xEndScreenRefresh(); |
|
| 459 | 378 |
PPU.HDMA = 0; |
| 460 | 379 |
// Bits 7 and 6 of $4212 are computed when read in S9xGetPPU. |
| 461 |
- #ifdef DEBUGGER |
|
| 462 |
- missing.dma_this_frame = 0; |
|
| 463 |
- #endif |
|
| 464 |
- IPPU.MaxBrightness = PPU.Brightness; |
|
| 465 |
- PPU.ForcedBlanking = (Memory.FillRAM[0x2100] >> 7) & 1; |
|
| 380 |
+ PPU.ForcedBlanking = !!((Memory.FillRAM[0x2100] >> 7) & 1); |
|
| 466 | 381 |
|
| 467 | 382 |
if (!PPU.ForcedBlanking) |
| 468 | 383 |
{
|
| 469 | 384 |
PPU.OAMAddr = PPU.SavedOAMAddr; |
| 470 | 385 |
|
| 471 |
- uint8_t tmp = 0; |
|
| 386 |
+ uint8_t tmp = 0; |
|
| 472 | 387 |
|
| 473 | 388 |
if (PPU.OAMPriorityRotation) |
| 474 | 389 |
tmp = (PPU.OAMAddr & 0xFE) >> 1; |
| 475 | 390 |
if ((PPU.OAMFlip & 1) || PPU.FirstSprite != tmp) |
| 476 |
- {
|
|
| 477 | 391 |
PPU.FirstSprite = tmp; |
| 478 |
- IPPU.OBJChanged = true; |
|
| 479 |
- } |
|
| 480 | 392 |
|
| 481 | 393 |
PPU.OAMFlip = 0; |
| 482 | 394 |
} |
| ... | ... |
@@ -490,18 +402,8 @@ void S9xDoHEventProcessing() |
| 490 | 402 |
CPU.NMILine = true; |
| 491 | 403 |
Timings.NMITriggerPos = 6 + 6; |
| 492 | 404 |
} |
| 493 |
- |
|
| 494 | 405 |
} |
| 495 | 406 |
|
| 496 |
- /*if (CPU.V_Counter == PPU.ScreenHeight + 3) // FIXME: not true |
|
| 497 |
- {
|
|
| 498 |
- if (Memory.FillRAM[0x4200] & 1) |
|
| 499 |
- S9xDoAutoJoypad(); |
|
| 500 |
- }*/ |
|
| 501 |
- |
|
| 502 |
- /*if (CPU.V_Counter == FIRST_VISIBLE_LINE) // V=1 |
|
| 503 |
- S9xStartScreenRefresh();*/ |
|
| 504 |
- |
|
| 505 | 407 |
S9xReschedule(); |
| 506 | 408 |
|
| 507 | 409 |
break; |
| ... | ... |
@@ -509,41 +411,21 @@ void S9xDoHEventProcessing() |
| 509 | 411 |
case HC_HDMA_INIT_EVENT: |
| 510 | 412 |
S9xReschedule(); |
| 511 | 413 |
|
| 512 |
- if (CPU.V_Counter == 0) |
|
| 513 |
- {
|
|
| 514 |
- #ifdef DEBUGGER |
|
| 515 |
- S9xTraceFormattedMessage("*** HDMA Init HC:%04d, Channel:%02x", CPU.Cycles, PPU.HDMA);
|
|
| 516 |
- #endif |
|
| 414 |
+ if (!CPU.V_Counter) |
|
| 517 | 415 |
S9xStartHDMA(); |
| 518 |
- } |
|
| 519 | 416 |
|
| 520 | 417 |
break; |
| 521 | 418 |
|
| 522 | 419 |
case HC_RENDER_EVENT: |
| 523 |
- /*if (CPU.V_Counter >= FIRST_VISIBLE_LINE && CPU.V_Counter <= PPU.ScreenHeight) |
|
| 524 |
- RenderLine((uint8_t) (CPU.V_Counter - FIRST_VISIBLE_LINE));*/ |
|
| 525 |
- |
|
| 526 | 420 |
S9xReschedule(); |
| 527 | 421 |
|
| 528 | 422 |
break; |
| 529 | 423 |
|
| 530 | 424 |
case HC_WRAM_REFRESH_EVENT: |
| 531 |
- #ifdef DEBUGGER |
|
| 532 |
- S9xTraceFormattedMessage("*** WRAM Refresh HC:%04d", CPU.Cycles);
|
|
| 533 |
- #endif |
|
| 534 |
- |
|
| 535 | 425 |
CPU.PrevCycles = CPU.Cycles; |
| 536 | 426 |
CPU.Cycles += SNES_WRAM_REFRESH_CYCLES; |
| 537 | 427 |
S9xCheckInterrupts(); |
| 538 | 428 |
|
| 539 | 429 |
S9xReschedule(); |
| 540 |
- |
|
| 541 |
- break; |
|
| 542 | 430 |
} |
| 543 |
- |
|
| 544 |
-#ifdef DEBUGGER |
|
| 545 |
- if (Settings.TraceHCEvent) |
|
| 546 |
- S9xTraceFormattedMessage("--- HC event rescheduled (%s) expected HC:%04d current HC:%04d",
|
|
| 547 |
- eventname[CPU.WhichEvent], CPU.NextEvent, CPU.Cycles); |
|
| 548 |
-#endif |
|
| 549 | 431 |
} |
| 1 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,549 @@ |
| 1 |
+/*********************************************************************************** |
|
| 2 |
+ Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. |
|
| 3 |
+ |
|
| 4 |
+ (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), |
|
| 5 |
+ Jerremy Koot (jkoot@snes9x.com) |
|
| 6 |
+ |
|
| 7 |
+ (c) Copyright 2002 - 2004 Matthew Kendora |
|
| 8 |
+ |
|
| 9 |
+ (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) |
|
| 10 |
+ |
|
| 11 |
+ (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) |
|
| 12 |
+ |
|
| 13 |
+ (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) |
|
| 14 |
+ |
|
| 15 |
+ (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), |
|
| 16 |
+ Kris Bleakley (codeviolation@hotmail.com) |
|
| 17 |
+ |
|
| 18 |
+ (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), |
|
| 19 |
+ Nach (n-a-c-h@users.sourceforge.net), |
|
| 20 |
+ |
|
| 21 |
+ (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) |
|
| 22 |
+ |
|
| 23 |
+ (c) Copyright 2006 - 2007 nitsuja |
|
| 24 |
+ |
|
| 25 |
+ (c) Copyright 2009 - 2011 BearOso, |
|
| 26 |
+ OV2 |
|
| 27 |
+ |
|
| 28 |
+ |
|
| 29 |
+ BS-X C emulator code |
|
| 30 |
+ (c) Copyright 2005 - 2006 Dreamer Nom, |
|
| 31 |
+ zones |
|
| 32 |
+ |
|
| 33 |
+ C4 x86 assembler and some C emulation code |
|
| 34 |
+ (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), |
|
| 35 |
+ Nach, |
|
| 36 |
+ zsKnight (zsknight@zsnes.com) |
|
| 37 |
+ |
|
| 38 |
+ C4 C++ code |
|
| 39 |
+ (c) Copyright 2003 - 2006 Brad Jorsch, |
|
| 40 |
+ Nach |
|
| 41 |
+ |
|
| 42 |
+ DSP-1 emulator code |
|
| 43 |
+ (c) Copyright 1998 - 2006 _Demo_, |
|
| 44 |
+ Andreas Naive (andreasnaive@gmail.com), |
|
| 45 |
+ Gary Henderson, |
|
| 46 |
+ Ivar (ivar@snes9x.com), |
|
| 47 |
+ John Weidman, |
|
| 48 |
+ Kris Bleakley, |
|
| 49 |
+ Matthew Kendora, |
|
| 50 |
+ Nach, |
|
| 51 |
+ neviksti (neviksti@hotmail.com) |
|
| 52 |
+ |
|
| 53 |
+ DSP-2 emulator code |
|
| 54 |
+ (c) Copyright 2003 John Weidman, |
|
| 55 |
+ Kris Bleakley, |
|
| 56 |
+ Lord Nightmare (lord_nightmare@users.sourceforge.net), |
|
| 57 |
+ Matthew Kendora, |
|
| 58 |
+ neviksti |
|
| 59 |
+ |
|
| 60 |
+ DSP-3 emulator code |
|
| 61 |
+ (c) Copyright 2003 - 2006 John Weidman, |
|
| 62 |
+ Kris Bleakley, |
|
| 63 |
+ Lancer, |
|
| 64 |
+ z80 gaiden |
|
| 65 |
+ |
|
| 66 |
+ DSP-4 emulator code |
|
| 67 |
+ (c) Copyright 2004 - 2006 Dreamer Nom, |
|
| 68 |
+ John Weidman, |
|
| 69 |
+ Kris Bleakley, |
|
| 70 |
+ Nach, |
|
| 71 |
+ z80 gaiden |
|
| 72 |
+ |
|
| 73 |
+ OBC1 emulator code |
|
| 74 |
+ (c) Copyright 2001 - 2004 zsKnight, |
|
| 75 |
+ pagefault (pagefault@zsnes.com), |
|
| 76 |
+ Kris Bleakley |
|
| 77 |
+ Ported from x86 assembler to C by sanmaiwashi |
|
| 78 |
+ |
|
| 79 |
+ SPC7110 and RTC C++ emulator code used in 1.39-1.51 |
|
| 80 |
+ (c) Copyright 2002 Matthew Kendora with research by |
|
| 81 |
+ zsKnight, |
|
| 82 |
+ John Weidman, |
|
| 83 |
+ Dark Force |
|
| 84 |
+ |
|
| 85 |
+ SPC7110 and RTC C++ emulator code used in 1.52+ |
|
| 86 |
+ (c) Copyright 2009 byuu, |
|
| 87 |
+ neviksti |
|
| 88 |
+ |
|
| 89 |
+ S-DD1 C emulator code |
|
| 90 |
+ (c) Copyright 2003 Brad Jorsch with research by |
|
| 91 |
+ Andreas Naive, |
|
| 92 |
+ John Weidman |
|
| 93 |
+ |
|
| 94 |
+ S-RTC C emulator code |
|
| 95 |
+ (c) Copyright 2001 - 2006 byuu, |
|
| 96 |
+ John Weidman |
|
| 97 |
+ |
|
| 98 |
+ ST010 C++ emulator code |
|
| 99 |
+ (c) Copyright 2003 Feather, |
|
| 100 |
+ John Weidman, |
|
| 101 |
+ Kris Bleakley, |
|
| 102 |
+ Matthew Kendora |
|
| 103 |
+ |
|
| 104 |
+ Super FX x86 assembler emulator code |
|
| 105 |
+ (c) Copyright 1998 - 2003 _Demo_, |
|
| 106 |
+ pagefault, |
|
| 107 |
+ zsKnight |
|
| 108 |
+ |
|
| 109 |
+ Super FX C emulator code |
|
| 110 |
+ (c) Copyright 1997 - 1999 Ivar, |
|
| 111 |
+ Gary Henderson, |
|
| 112 |
+ John Weidman |
|
| 113 |
+ |
|
| 114 |
+ Sound emulator code used in 1.5-1.51 |
|
| 115 |
+ (c) Copyright 1998 - 2003 Brad Martin |
|
| 116 |
+ (c) Copyright 1998 - 2006 Charles Bilyue' |
|
| 117 |
+ |
|
| 118 |
+ Sound emulator code used in 1.52+ |
|
| 119 |
+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) |
|
| 120 |
+ |
|
| 121 |
+ SH assembler code partly based on x86 assembler code |
|
| 122 |
+ (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) |
|
| 123 |
+ |
|
| 124 |
+ 2xSaI filter |
|
| 125 |
+ (c) Copyright 1999 - 2001 Derek Liauw Kie Fa |
|
| 126 |
+ |
|
| 127 |
+ HQ2x, HQ3x, HQ4x filters |
|
| 128 |
+ (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) |
|
| 129 |
+ |
|
| 130 |
+ NTSC filter |
|
| 131 |
+ (c) Copyright 2006 - 2007 Shay Green |
|
| 132 |
+ |
|
| 133 |
+ GTK+ GUI code |
|
| 134 |
+ (c) Copyright 2004 - 2011 BearOso |
|
| 135 |
+ |
|
| 136 |
+ Win32 GUI code |
|
| 137 |
+ (c) Copyright 2003 - 2006 blip, |
|
| 138 |
+ funkyass, |
|
| 139 |
+ Matthew Kendora, |
|
| 140 |
+ Nach, |
|
| 141 |
+ nitsuja |
|
| 142 |
+ (c) Copyright 2009 - 2011 OV2 |
|
| 143 |
+ |
|
| 144 |
+ Mac OS GUI code |
|
| 145 |
+ (c) Copyright 1998 - 2001 John Stiles |
|
| 146 |
+ (c) Copyright 2001 - 2011 zones |
|
| 147 |
+ |
|
| 148 |
+ |
|
| 149 |
+ Specific ports contains the works of other authors. See headers in |
|
| 150 |
+ individual files. |
|
| 151 |
+ |
|
| 152 |
+ |
|
| 153 |
+ Snes9x homepage: http://www.snes9x.com/ |
|
| 154 |
+ |
|
| 155 |
+ Permission to use, copy, modify and/or distribute Snes9x in both binary |
|
| 156 |
+ and source form, for non-commercial purposes, is hereby granted without |
|
| 157 |
+ fee, providing that this license information and copyright notice appear |
|
| 158 |
+ with all copies and any derived work. |
|
| 159 |
+ |
|
| 160 |
+ This software is provided 'as-is', without any express or implied |
|
| 161 |
+ warranty. In no event shall the authors be held liable for any damages |
|
| 162 |
+ arising from the use of this software or it's derivatives. |
|
| 163 |
+ |
|
| 164 |
+ Snes9x is freeware for PERSONAL USE only. Commercial users should |
|
| 165 |
+ seek permission of the copyright holders first. Commercial use includes, |
|
| 166 |
+ but is not limited to, charging money for Snes9x or software derived from |
|
| 167 |
+ Snes9x, including Snes9x or derivatives in commercial game bundles, and/or |
|
| 168 |
+ using Snes9x as a promotion for your commercial product. |
|
| 169 |
+ |
|
| 170 |
+ The copyright holders request that bug fixes and improvements to the code |
|
| 171 |
+ should be forwarded to them so everyone can benefit from the modifications |
|
| 172 |
+ in future versions. |
|
| 173 |
+ |
|
| 174 |
+ Super NES and Super Nintendo Entertainment System are trademarks of |
|
| 175 |
+ Nintendo Co., Limited and its subsidiary companies. |
|
| 176 |
+ ***********************************************************************************/ |
|
| 177 |
+ |
|
| 178 |
+#include "snes9x.h" |
|
| 179 |
+#include "memmap.h" |
|
| 180 |
+#include "cpuops.h" |
|
| 181 |
+#include "dma.h" |
|
| 182 |
+#include "apu/apu.h" |
|
| 183 |
+//#include "fxemu.h" |
|
| 184 |
+//#include "snapshot.h" |
|
| 185 |
+#ifdef DEBUGGER |
|
| 186 |
+#include "debug.h" |
|
| 187 |
+#include "missing.h" |
|
| 188 |
+#endif |
|
| 189 |
+ |
|
| 190 |
+static inline void S9xReschedule() |
|
| 191 |
+{
|
|
| 192 |
+ switch (CPU.WhichEvent) |
|
| 193 |
+ {
|
|
| 194 |
+ case HC_HBLANK_START_EVENT: |
|
| 195 |
+ CPU.WhichEvent = HC_HDMA_START_EVENT; |
|
| 196 |
+ CPU.NextEvent = Timings.HDMAStart; |
|
| 197 |
+ break; |
|
| 198 |
+ |
|
| 199 |
+ case HC_HDMA_START_EVENT: |
|
| 200 |
+ CPU.WhichEvent = HC_HCOUNTER_MAX_EVENT; |
|
| 201 |
+ CPU.NextEvent = Timings.H_Max; |
|
| 202 |
+ break; |
|
| 203 |
+ |
|
| 204 |
+ case HC_HCOUNTER_MAX_EVENT: |
|
| 205 |
+ CPU.WhichEvent = HC_HDMA_INIT_EVENT; |
|
| 206 |
+ CPU.NextEvent = Timings.HDMAInit; |
|
| 207 |
+ break; |
|
| 208 |
+ |
|
| 209 |
+ case HC_HDMA_INIT_EVENT: |
|
| 210 |
+ CPU.WhichEvent = HC_RENDER_EVENT; |
|
| 211 |
+ CPU.NextEvent = Timings.RenderPos; |
|
| 212 |
+ break; |
|
| 213 |
+ |
|
| 214 |
+ case HC_RENDER_EVENT: |
|
| 215 |
+ CPU.WhichEvent = HC_WRAM_REFRESH_EVENT; |
|
| 216 |
+ CPU.NextEvent = Timings.WRAMRefreshPos; |
|
| 217 |
+ break; |
|
| 218 |
+ |
|
| 219 |
+ case HC_WRAM_REFRESH_EVENT: |
|
| 220 |
+ CPU.WhichEvent = HC_HBLANK_START_EVENT; |
|
| 221 |
+ CPU.NextEvent = Timings.HBlankStart; |
|
| 222 |
+ break; |
|
| 223 |
+ } |
|
| 224 |
+} |
|
| 225 |
+ |
|
| 226 |
+void S9xMainLoop() |
|
| 227 |
+{
|
|
| 228 |
+ for (;;) |
|
| 229 |
+ {
|
|
| 230 |
+ if (CPU.NMILine) |
|
| 231 |
+ {
|
|
| 232 |
+ if (Timings.NMITriggerPos <= CPU.Cycles) |
|
| 233 |
+ {
|
|
| 234 |
+ CPU.NMILine = false; |
|
| 235 |
+ Timings.NMITriggerPos = 0xffff; |
|
| 236 |
+ if (CPU.WaitingForInterrupt) |
|
| 237 |
+ {
|
|
| 238 |
+ CPU.WaitingForInterrupt = false; |
|
| 239 |
+ Registers.PCw++; |
|
| 240 |
+ } |
|
| 241 |
+ |
|
| 242 |
+ S9xOpcode_NMI(); |
|
| 243 |
+ } |
|
| 244 |
+ } |
|
| 245 |
+ |
|
| 246 |
+ if (CPU.IRQTransition || CPU.IRQExternal) |
|
| 247 |
+ {
|
|
| 248 |
+ if (CPU.IRQPending) |
|
| 249 |
+ CPU.IRQPending--; |
|
| 250 |
+ else |
|
| 251 |
+ {
|
|
| 252 |
+ if (CPU.WaitingForInterrupt) |
|
| 253 |
+ {
|
|
| 254 |
+ CPU.WaitingForInterrupt = false; |
|
| 255 |
+ Registers.PCw++; |
|
| 256 |
+ } |
|
| 257 |
+ |
|
| 258 |
+ CPU.IRQTransition = false; |
|
| 259 |
+ CPU.IRQPending = Timings.IRQPendCount; |
|
| 260 |
+ |
|
| 261 |
+ if (!CheckFlag(IRQ)) |
|
| 262 |
+ S9xOpcode_IRQ(); |
|
| 263 |
+ } |
|
| 264 |
+ } |
|
| 265 |
+ |
|
| 266 |
+ #ifdef DEBUGGER |
|
| 267 |
+ if ((CPU.Flags & BREAK_FLAG) && !(CPU.Flags & SINGLE_STEP_FLAG)) |
|
| 268 |
+ {
|
|
| 269 |
+ for (int Break = 0; Break != 6; Break++) |
|
| 270 |
+ {
|
|
| 271 |
+ if (S9xBreakpoint[Break].Enabled && |
|
| 272 |
+ S9xBreakpoint[Break].Bank == Registers.PB && |
|
| 273 |
+ S9xBreakpoint[Break].Address == Registers.PCw) |
|
| 274 |
+ {
|
|
| 275 |
+ if (S9xBreakpoint[Break].Enabled == 2) |
|
| 276 |
+ S9xBreakpoint[Break].Enabled = true; |
|
| 277 |
+ else |
|
| 278 |
+ CPU.Flags |= DEBUG_MODE_FLAG; |
|
| 279 |
+ } |
|
| 280 |
+ } |
|
| 281 |
+ } |
|
| 282 |
+ |
|
| 283 |
+ if (CPU.Flags & DEBUG_MODE_FLAG) |
|
| 284 |
+ break; |
|
| 285 |
+ |
|
| 286 |
+ if (CPU.Flags & TRACE_FLAG) |
|
| 287 |
+ S9xTrace(); |
|
| 288 |
+ |
|
| 289 |
+ if (CPU.Flags & SINGLE_STEP_FLAG) |
|
| 290 |
+ {
|
|
| 291 |
+ CPU.Flags &= ~SINGLE_STEP_FLAG; |
|
| 292 |
+ CPU.Flags |= DEBUG_MODE_FLAG; |
|
| 293 |
+ } |
|
| 294 |
+ #endif |
|
| 295 |
+ |
|
| 296 |
+ if (CPU.Flags & SCAN_KEYS_FLAG) |
|
| 297 |
+ break; |
|
| 298 |
+ |
|
| 299 |
+ register uint8_t Op; |
|
| 300 |
+ register struct SOpcodes *Opcodes; |
|
| 301 |
+ |
|
| 302 |
+ if (CPU.PCBase) |
|
| 303 |
+ {
|
|
| 304 |
+ Op = CPU.PCBase[Registers.PCw]; |
|
| 305 |
+ CPU.PrevCycles = CPU.Cycles; |
|
| 306 |
+ CPU.Cycles += CPU.MemSpeed; |
|
| 307 |
+ S9xCheckInterrupts(); |
|
| 308 |
+ Opcodes = ICPU.S9xOpcodes; |
|
| 309 |
+ } |
|
| 310 |
+ else |
|
| 311 |
+ {
|
|
| 312 |
+ Op = S9xGetByte(Registers.PBPC); |
|
| 313 |
+ OpenBus = Op; |
|
| 314 |
+ Opcodes = S9xOpcodesSlow; |
|
| 315 |
+ } |
|
| 316 |
+ |
|
| 317 |
+ if ((Registers.PCw & MEMMAP_MASK) + ICPU.S9xOpLengths[Op] >= MEMMAP_BLOCK_SIZE) |
|
| 318 |
+ {
|
|
| 319 |
+ uint8_t *oldPCBase = CPU.PCBase; |
|
| 320 |
+ |
|
| 321 |
+ CPU.PCBase = S9xGetBasePointer(ICPU.ShiftedPB + ((uint16_t) (Registers.PCw + 4))); |
|
| 322 |
+ if (oldPCBase != CPU.PCBase || (Registers.PCw & ~MEMMAP_MASK) == (0xffff & ~MEMMAP_MASK)) |
|
| 323 |
+ Opcodes = S9xOpcodesSlow; |
|
| 324 |
+ } |
|
| 325 |
+ |
|
| 326 |
+ Registers.PCw++; |
|
| 327 |
+ (*Opcodes[Op].S9xOpcode)(); |
|
| 328 |
+ |
|
| 329 |
+ /*if (Settings.SA1) |
|
| 330 |
+ S9xSA1MainLoop();*/ |
|
| 331 |
+ } |
|
| 332 |
+ |
|
| 333 |
+ S9xPackStatus(); |
|
| 334 |
+ |
|
| 335 |
+ if (CPU.Flags & SCAN_KEYS_FLAG) |
|
| 336 |
+ {
|
|
| 337 |
+ /*#ifdef DEBUGGER |
|
| 338 |
+ if (!(CPU.Flags & FRAME_ADVANCE_FLAG)) |
|
| 339 |
+ #endif |
|
| 340 |
+ S9xSyncSpeed();*/ |
|
| 341 |
+ CPU.Flags &= ~SCAN_KEYS_FLAG; |
|
| 342 |
+ } |
|
| 343 |
+} |
|
| 344 |
+ |
|
| 345 |
+void S9xDoHEventProcessing() |
|
| 346 |
+{
|
|
| 347 |
+#ifdef DEBUGGER |
|
| 348 |
+ static char eventname[7][32] = |
|
| 349 |
+ {
|
|
| 350 |
+ "", |
|
| 351 |
+ "HC_HBLANK_START_EVENT", |
|
| 352 |
+ "HC_HDMA_START_EVENT ", |
|
| 353 |
+ "HC_HCOUNTER_MAX_EVENT", |
|
| 354 |
+ "HC_HDMA_INIT_EVENT ", |
|
| 355 |
+ "HC_RENDER_EVENT ", |
|
| 356 |
+ "HC_WRAM_REFRESH_EVENT" |
|
| 357 |
+ }; |
|
| 358 |
+#endif |
|
| 359 |
+ |
|
| 360 |
+#ifdef DEBUGGER |
|
| 361 |
+ if (Settings.TraceHCEvent) |
|
| 362 |
+ S9xTraceFormattedMessage("--- HC event processing (%s) expected HC:%04d executed HC:%04d",
|
|
| 363 |
+ eventname[CPU.WhichEvent], CPU.NextEvent, CPU.Cycles); |
|
| 364 |
+#endif |
|
| 365 |
+ |
|
| 366 |
+ switch (CPU.WhichEvent) |
|
| 367 |
+ {
|
|
| 368 |
+ case HC_HBLANK_START_EVENT: |
|
| 369 |
+ S9xReschedule(); |
|
| 370 |
+ break; |
|
| 371 |
+ |
|
| 372 |
+ case HC_HDMA_START_EVENT: |
|
| 373 |
+ S9xReschedule(); |
|
| 374 |
+ |
|
| 375 |
+ if (PPU.HDMA && CPU.V_Counter <= PPU.ScreenHeight) |
|
| 376 |
+ {
|
|
| 377 |
+ #ifdef DEBUGGER |
|
| 378 |
+ S9xTraceFormattedMessage("*** HDMA Transfer HC:%04d, Channel:%02x", CPU.Cycles, PPU.HDMA);
|
|
| 379 |
+ #endif |
|
| 380 |
+ PPU.HDMA = S9xDoHDMA(PPU.HDMA); |
|
| 381 |
+ } |
|
| 382 |
+ |
|
| 383 |
+ break; |
|
| 384 |
+ |
|
| 385 |
+ case HC_HCOUNTER_MAX_EVENT: |
|
| 386 |
+ /*if (Settings.SuperFX) |
|
| 387 |
+ {
|
|
| 388 |
+ if (!SuperFX.oneLineDone) |
|
| 389 |
+ S9xSuperFXExec(); |
|
| 390 |
+ SuperFX.oneLineDone = false; |
|
| 391 |
+ }*/ |
|
| 392 |
+ |
|
| 393 |
+ S9xAPUEndScanline(); |
|
| 394 |
+ CPU.Cycles -= Timings.H_Max; |
|
| 395 |
+ CPU.PrevCycles -= Timings.H_Max; |
|
| 396 |
+ S9xAPUSetReferenceTime(CPU.Cycles); |
|
| 397 |
+ |
|
| 398 |
+ if ((Timings.NMITriggerPos != 0xffff) && (Timings.NMITriggerPos >= Timings.H_Max)) |
|
| 399 |
+ Timings.NMITriggerPos -= Timings.H_Max; |
|
| 400 |
+ |
|
| 401 |
+ CPU.V_Counter++; |
|
| 402 |
+ if (CPU.V_Counter >= Timings.V_Max) // V ranges from 0 to Timings.V_Max - 1 |
|
| 403 |
+ {
|
|
| 404 |
+ CPU.V_Counter = 0; |
|
| 405 |
+ Timings.InterlaceField ^= 1; |
|
| 406 |
+ |
|
| 407 |
+ // From byuu: |
|
| 408 |
+ // [NTSC] |
|
| 409 |
+ // interlace mode has 525 scanlines: 263 on the even frame, and 262 on the odd. |
|
| 410 |
+ // non-interlace mode has 524 scanlines: 262 scanlines on both even and odd frames. |
|
| 411 |
+ // [PAL] <PAL info is unverified on hardware> |
|
| 412 |
+ // interlace mode has 625 scanlines: 313 on the even frame, and 312 on the odd. |
|
| 413 |
+ // non-interlace mode has 624 scanlines: 312 scanlines on both even and odd frames. |
|
| 414 |
+ if (IPPU.Interlace && !Timings.InterlaceField) |
|
| 415 |
+ Timings.V_Max = Timings.V_Max_Master + 1; // 263 (NTSC), 313?(PAL) |
|
| 416 |
+ else |
|
| 417 |
+ Timings.V_Max = Timings.V_Max_Master; // 262 (NTSC), 312?(PAL) |
|
| 418 |
+ |
|
| 419 |
+ Memory.FillRAM[0x213F] ^= 0x80; |
|
| 420 |
+ PPU.RangeTimeOver = 0; |
|
| 421 |
+ |
|
| 422 |
+ // FIXME: reading $4210 will wait 2 cycles, then perform reading, then wait 4 more cycles. |
|
| 423 |
+ Memory.FillRAM[0x4210] = Model->_5A22; |
|
| 424 |
+ CPU.NMILine = false; |
|
| 425 |
+ Timings.NMITriggerPos = 0xffff; |
|
| 426 |
+ |
|
| 427 |
+ ICPU.Frame++; |
|
| 428 |
+ PPU.HVBeamCounterLatched = 0; |
|
| 429 |
+ CPU.Flags |= SCAN_KEYS_FLAG; |
|
| 430 |
+ } |
|
| 431 |
+ |
|
| 432 |
+ // From byuu: |
|
| 433 |
+ // In non-interlace mode, there are 341 dots per scanline, and 262 scanlines per frame. |
|
| 434 |
+ // On odd frames, scanline 240 is one dot short. |
|
| 435 |
+ // In interlace mode, there are always 341 dots per scanline. Even frames have 263 scanlines, |
|
| 436 |
+ // and odd frames have 262 scanlines. |
|
| 437 |
+ // Interlace mode scanline 240 on odd frames is not missing a dot. |
|
| 438 |
+ if (CPU.V_Counter == 240 && !IPPU.Interlace && Timings.InterlaceField) // V=240 |
|
| 439 |
+ Timings.H_Max = Timings.H_Max_Master - ONE_DOT_CYCLE; // HC=1360 |
|
| 440 |
+ else |
|
| 441 |
+ Timings.H_Max = Timings.H_Max_Master; // HC=1364 |
|
| 442 |
+ |
|
| 443 |
+ if (Model->_5A22 == 2) |
|
| 444 |
+ {
|
|
| 445 |
+ if (CPU.V_Counter != 240 || IPPU.Interlace || !Timings.InterlaceField) // V=240 |
|
| 446 |
+ {
|
|
| 447 |
+ if (Timings.WRAMRefreshPos == SNES_WRAM_REFRESH_HC_v2 - ONE_DOT_CYCLE) // HC=534 |
|
| 448 |
+ Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2; // HC=538 |
|
| 449 |
+ else |
|
| 450 |
+ Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2 - ONE_DOT_CYCLE; // HC=534 |
|
| 451 |
+ } |
|
| 452 |
+ } |
|
| 453 |
+ else |
|
| 454 |
+ Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v1; |
|
| 455 |
+ |
|
| 456 |
+ if (CPU.V_Counter == PPU.ScreenHeight + FIRST_VISIBLE_LINE) // VBlank starts from V=225(240). |
|
| 457 |
+ {
|
|
| 458 |
+ //S9xEndScreenRefresh(); |
|
| 459 |
+ PPU.HDMA = 0; |
|
| 460 |
+ // Bits 7 and 6 of $4212 are computed when read in S9xGetPPU. |
|
| 461 |
+ #ifdef DEBUGGER |
|
| 462 |
+ missing.dma_this_frame = 0; |
|
| 463 |
+ #endif |
|
| 464 |
+ IPPU.MaxBrightness = PPU.Brightness; |
|
| 465 |
+ PPU.ForcedBlanking = (Memory.FillRAM[0x2100] >> 7) & 1; |
|
| 466 |
+ |
|
| 467 |
+ if (!PPU.ForcedBlanking) |
|
| 468 |
+ {
|
|
| 469 |
+ PPU.OAMAddr = PPU.SavedOAMAddr; |
|
| 470 |
+ |
|
| 471 |
+ uint8_t tmp = 0; |
|
| 472 |
+ |
|
| 473 |
+ if (PPU.OAMPriorityRotation) |
|
| 474 |
+ tmp = (PPU.OAMAddr & 0xFE) >> 1; |
|
| 475 |
+ if ((PPU.OAMFlip & 1) || PPU.FirstSprite != tmp) |
|
| 476 |
+ {
|
|
| 477 |
+ PPU.FirstSprite = tmp; |
|
| 478 |
+ IPPU.OBJChanged = true; |
|
| 479 |
+ } |
|
| 480 |
+ |
|
| 481 |
+ PPU.OAMFlip = 0; |
|
| 482 |
+ } |
|
| 483 |
+ |
|
| 484 |
+ // FIXME: writing to $4210 will wait 6 cycles. |
|
| 485 |
+ Memory.FillRAM[0x4210] = 0x80 | Model->_5A22; |
|
| 486 |
+ if (Memory.FillRAM[0x4200] & 0x80) |
|
| 487 |
+ {
|
|
| 488 |
+ // FIXME: triggered at HC=6, checked just before the final CPU cycle, |
|
| 489 |
+ // then, when to call S9xOpcode_NMI()? |
|
| 490 |
+ CPU.NMILine = true; |
|
| 491 |
+ Timings.NMITriggerPos = 6 + 6; |
|
| 492 |
+ } |
|
| 493 |
+ |
|
| 494 |
+ } |
|
| 495 |
+ |
|
| 496 |
+ /*if (CPU.V_Counter == PPU.ScreenHeight + 3) // FIXME: not true |
|
| 497 |
+ {
|
|
| 498 |
+ if (Memory.FillRAM[0x4200] & 1) |
|
| 499 |
+ S9xDoAutoJoypad(); |
|
| 500 |
+ }*/ |
|
| 501 |
+ |
|
| 502 |
+ /*if (CPU.V_Counter == FIRST_VISIBLE_LINE) // V=1 |
|
| 503 |
+ S9xStartScreenRefresh();*/ |
|
| 504 |
+ |
|
| 505 |
+ S9xReschedule(); |
|
| 506 |
+ |
|
| 507 |
+ break; |
|
| 508 |
+ |
|
| 509 |
+ case HC_HDMA_INIT_EVENT: |
|
| 510 |
+ S9xReschedule(); |
|
| 511 |
+ |
|
| 512 |
+ if (CPU.V_Counter == 0) |
|
| 513 |
+ {
|
|
| 514 |
+ #ifdef DEBUGGER |
|
| 515 |
+ S9xTraceFormattedMessage("*** HDMA Init HC:%04d, Channel:%02x", CPU.Cycles, PPU.HDMA);
|
|
| 516 |
+ #endif |
|
| 517 |
+ S9xStartHDMA(); |
|
| 518 |
+ } |
|
| 519 |
+ |
|
| 520 |
+ break; |
|
| 521 |
+ |
|
| 522 |
+ case HC_RENDER_EVENT: |
|
| 523 |
+ /*if (CPU.V_Counter >= FIRST_VISIBLE_LINE && CPU.V_Counter <= PPU.ScreenHeight) |
|
| 524 |
+ RenderLine((uint8_t) (CPU.V_Counter - FIRST_VISIBLE_LINE));*/ |
|
| 525 |
+ |
|
| 526 |
+ S9xReschedule(); |
|
| 527 |
+ |
|
| 528 |
+ break; |
|
| 529 |
+ |
|
| 530 |
+ case HC_WRAM_REFRESH_EVENT: |
|
| 531 |
+ #ifdef DEBUGGER |
|
| 532 |
+ S9xTraceFormattedMessage("*** WRAM Refresh HC:%04d", CPU.Cycles);
|
|
| 533 |
+ #endif |
|
| 534 |
+ |
|
| 535 |
+ CPU.PrevCycles = CPU.Cycles; |
|
| 536 |
+ CPU.Cycles += SNES_WRAM_REFRESH_CYCLES; |
|
| 537 |
+ S9xCheckInterrupts(); |
|
| 538 |
+ |
|
| 539 |
+ S9xReschedule(); |
|
| 540 |
+ |
|
| 541 |
+ break; |
|
| 542 |
+ } |
|
| 543 |
+ |
|
| 544 |
+#ifdef DEBUGGER |
|
| 545 |
+ if (Settings.TraceHCEvent) |
|
| 546 |
+ S9xTraceFormattedMessage("--- HC event rescheduled (%s) expected HC:%04d current HC:%04d",
|
|
| 547 |
+ eventname[CPU.WhichEvent], CPU.NextEvent, CPU.Cycles); |
|
| 548 |
+#endif |
|
| 549 |
+} |