diff --git a/stella/Todo.txt b/stella/Todo.txt index d7701f67b..08989c8fa 100644 --- a/stella/Todo.txt +++ b/stella/Todo.txt @@ -33,7 +33,7 @@ X * Add infrastructure to show all info gathered from a ROM (similar to what is currently displayed on the commandline). Add a UI part for this, so users aren't forced to use the commandline to see it. - * Fix issue with paddle support in Activision Casino ROM. +X * Fix issue with paddle support in Activision Casino ROM. * More work to the ROM launcher, including at least the following: X (1) Only show files with certain extensions (including a UI part to diff --git a/stella/src/emucore/TIA.cxx b/stella/src/emucore/TIA.cxx index 51130b75a..a96919500 100644 --- a/stella/src/emucore/TIA.cxx +++ b/stella/src/emucore/TIA.cxx @@ -13,10 +13,11 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: TIA.cxx,v 1.98 2009-01-12 01:07:29 stephena Exp $ +// $Id: TIA.cxx,v 1.99 2009-01-13 01:18:24 stephena Exp $ //============================================================================ //#define DEBUG_HMOVE +//#define NO_HMOVE_FIXES #include #include @@ -198,8 +199,9 @@ void TIA::reset() myFloatTIAOutputPins = mySettings.getBool("tiafloat"); myAutoFrameEnabled = (mySettings.getInt("framerate") <= 0); + myFramerate = myConsole.getFramerate(); - if(myConsole.getFramerate() > 55.0) // NTSC + if(myFramerate > 55.0) // NTSC { myColorLossEnabled = false; myMaximumNumberOfScanlines = 290; @@ -596,10 +598,9 @@ inline void TIA::endFrame() // Recalculate framerate. attempting to auto-correct for scanline 'jumps' if(myFrameCounter % 32 == 0 && myAutoFrameEnabled) { - float framerate = - (myScanlineCountForLastFrame > 285 ? 15600.0 : 15720.0) / - myScanlineCountForLastFrame; - myConsole.setFramerate(framerate); + myFramerate = (myScanlineCountForLastFrame > 285 ? 15600.0 : 15720.0) / + myScanlineCountForLastFrame; + myConsole.setFramerate(myFramerate); } myFrameGreyed = false; @@ -1973,176 +1974,125 @@ void TIA::greyOutFrame() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::clearBuffers() { - for(uInt32 i = 0; i < 160 * 300; ++i) + memset(myCurrentFrameBuffer, 0, 160 * 300); + memset(myPreviousFrameBuffer, 0, 160 * 300); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +inline uInt8 TIA::dumpedInputPort(int resistance) +{ + if(resistance == Controller::minimumResistance) { - myCurrentFrameBuffer[i] = myPreviousFrameBuffer[i] = 0; + return 0x80; } + else if((resistance == Controller::maximumResistance) || myDumpEnabled) + { + return 0x00; + } + else + { + uInt32 needed = (uInt32) (1.6 * resistance * 0.01e-6 * + myScanlineCountForLastFrame * 228 * myFramerate / 3); + if((mySystem->cycles() - myDumpDisabledCycle) > needed) + { + return 0x80; + } + else + { + return 0x00; + } + } + return 0x00; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIA::peek(uInt16 addr) { + // TODO - convert all constants to enums (TIA.cs/530) + // Update frame to current color clock before we look at anything! updateFrame(mySystem->cycles() * 3); - uInt8 noise = mySystem->getDataBusState() & 0x3F; - - // On certain CMOS EPROM chips the unused TIA pins on a read are not - // floating but pulled high. Programmers might want to check their - // games for compatibility, so we make this optional. - if(!myFloatTIAOutputPins) noise = 0x3F; + uInt8 retval = 0x00; switch(addr & 0x000f) { - case 0x00: // CXM0P - return ((myCollision & 0x0001) ? 0x80 : 0x00) | - ((myCollision & 0x0002) ? 0x40 : 0x00) | noise; + case CXM0P: + retval = ((myCollision & 0x0001) ? 0x80 : 0x00) | + ((myCollision & 0x0002) ? 0x40 : 0x00); + break; - case 0x01: // CXM1P - return ((myCollision & 0x0004) ? 0x80 : 0x00) | - ((myCollision & 0x0008) ? 0x40 : 0x00) | noise; + case CXM1P: + retval = ((myCollision & 0x0004) ? 0x80 : 0x00) | + ((myCollision & 0x0008) ? 0x40 : 0x00); + break; - case 0x02: // CXP0FB - return ((myCollision & 0x0010) ? 0x80 : 0x00) | - ((myCollision & 0x0020) ? 0x40 : 0x00) | noise; + case CXP0FB: + retval = ((myCollision & 0x0010) ? 0x80 : 0x00) | + ((myCollision & 0x0020) ? 0x40 : 0x00); + break; - case 0x03: // CXP1FB - return ((myCollision & 0x0040) ? 0x80 : 0x00) | - ((myCollision & 0x0080) ? 0x40 : 0x00) | noise; + case CXP1FB: + retval = ((myCollision & 0x0040) ? 0x80 : 0x00) | + ((myCollision & 0x0080) ? 0x40 : 0x00); + break; - case 0x04: // CXM0FB - return ((myCollision & 0x0100) ? 0x80 : 0x00) | - ((myCollision & 0x0200) ? 0x40 : 0x00) | noise; + case CXM0FB: + retval = ((myCollision & 0x0100) ? 0x80 : 0x00) | + ((myCollision & 0x0200) ? 0x40 : 0x00); + break; - case 0x05: // CXM1FB - return ((myCollision & 0x0400) ? 0x80 : 0x00) | - ((myCollision & 0x0800) ? 0x40 : 0x00) | noise; + case CXM1FB: + retval = ((myCollision & 0x0400) ? 0x80 : 0x00) | + ((myCollision & 0x0800) ? 0x40 : 0x00); + break; - case 0x06: // CXBLPF - return ((myCollision & 0x1000) ? 0x80 : 0x00) | noise; + case CXBLPF: + retval = (myCollision & 0x1000) ? 0x80 : 0x00; + break; - case 0x07: // CXPPMM - return ((myCollision & 0x2000) ? 0x80 : 0x00) | - ((myCollision & 0x4000) ? 0x40 : 0x00) | noise; + case CXPPMM: + retval = ((myCollision & 0x2000) ? 0x80 : 0x00) | + ((myCollision & 0x4000) ? 0x40 : 0x00); + break; - case 0x08: // INPT0 - { - Int32 r = myConsole.controller(Controller::Left).read(Controller::Nine); - if(r == Controller::minimumResistance) - { - return 0x80 | noise; - } - else if((r == Controller::maximumResistance) || myDumpEnabled) - { - return noise; - } - else - { - double t = (1.5327 * r * 0.01E-6); - uInt32 needed = (uInt32)(t * 1.19E6); - if((mySystem->cycles() - myDumpDisabledCycle) > needed) - { - return 0x80 | noise; - } - else - { - return noise; - } - } - } + case INPT0: + retval = dumpedInputPort(myConsole.controller(Controller::Left).read(Controller::Nine)); + break; - case 0x09: // INPT1 - { - Int32 r = myConsole.controller(Controller::Left).read(Controller::Five); - if(r == Controller::minimumResistance) - { - return 0x80 | noise; - } - else if((r == Controller::maximumResistance) || myDumpEnabled) - { - return noise; - } - else - { - double t = (1.5327 * r * 0.01E-6); - uInt32 needed = (uInt32)(t * 1.19E6); - if((mySystem->cycles() - myDumpDisabledCycle) > needed) - { - return 0x80 | noise; - } - else - { - return noise; - } - } - } + case INPT1: + retval = dumpedInputPort(myConsole.controller(Controller::Left).read(Controller::Five)); + break; - case 0x0A: // INPT2 - { - Int32 r = myConsole.controller(Controller::Right).read(Controller::Nine); - if(r == Controller::minimumResistance) - { - return 0x80 | noise; - } - else if((r == Controller::maximumResistance) || myDumpEnabled) - { - return noise; - } - else - { - double t = (1.5327 * r * 0.01E-6); - uInt32 needed = (uInt32)(t * 1.19E6); - if((mySystem->cycles() - myDumpDisabledCycle) > needed) - { - return 0x80 | noise; - } - else - { - return noise; - } - } - } + case INPT2: + retval = dumpedInputPort(myConsole.controller(Controller::Right).read(Controller::Nine)); + break; - case 0x0B: // INPT3 - { - Int32 r = myConsole.controller(Controller::Right).read(Controller::Five); - if(r == Controller::minimumResistance) - { - return 0x80 | noise; - } - else if((r == Controller::maximumResistance) || myDumpEnabled) - { - return noise; - } - else - { - double t = (1.5327 * r * 0.01E-6); - uInt32 needed = (uInt32)(t * 1.19E6); - if((mySystem->cycles() - myDumpDisabledCycle) > needed) - { - return 0x80 | noise; - } - else - { - return noise; - } - } - } + case INPT3: + retval = dumpedInputPort(myConsole.controller(Controller::Right).read(Controller::Five)); + break; - case 0x0C: // INPT4 - return myConsole.controller(Controller::Left).read(Controller::Six) ? - (0x80 | noise) : noise; + case INPT4: + retval = myConsole.controller(Controller::Left).read(Controller::Six) ? + 0x80 : 0x00; + break; - case 0x0D: // INPT5 - return myConsole.controller(Controller::Right).read(Controller::Six) ? - (0x80 | noise) : noise; - - case 0x0e: - return noise; + case INPT5: + retval = myConsole.controller(Controller::Right).read(Controller::Six) ? + 0x80 : 0x00; + break; + case 0x0e: // TODO - document this address default: - return noise; + break; } + + // On certain CMOS EPROM chips the unused TIA pins on a read are not + // floating but pulled high. Programmers might want to check their + // games for compatibility, so we make this optional. + retval |= myFloatTIAOutputPins ? (mySystem->getDataBusState() & 0x3F) : 0x3F; + + return retval; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2173,7 +2123,7 @@ void TIA::poke(uInt16 addr, uInt8 value) switch(addr) { - case 0x00: // Vertical sync set-clear + case VSYNC: // Vertical sync set-clear { myVSYNC = value; @@ -2196,7 +2146,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x01: // Vertical blank set-clear + case VBLANK: // Vertical blank set-clear { // Is the dump to ground path being set for I0, I1, I2, and I3? if(!(myVBLANK & 0x80) && (value & 0x80)) @@ -2215,7 +2165,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x02: // Wait for leading edge of HBLANK + case WSYNC: // Wait for leading edge of HBLANK { // It appears that the 6507 only halts during a read cycle so // we test here for follow-on writes which should be ignored as @@ -2232,13 +2182,13 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x03: // Reset horizontal sync counter + case RSYNC: // Reset horizontal sync counter { // cerr << "TIA Poke: " << hex << addr << endl; break; } - case 0x04: // Number-size of player-missle 0 + case NUSIZ0: // Number-size of player-missle 0 { myNUSIZ0 = value; @@ -2254,7 +2204,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x05: // Number-size of player-missle 1 + case NUSIZ1: // Number-size of player-missle 1 { myNUSIZ1 = value; @@ -2270,7 +2220,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x06: // Color-Luminance Player 0 + case COLUP0: // Color-Luminance Player 0 { uInt32 color = (uInt32)(value & 0xfe); if(myColorLossEnabled && (myScanlineCountForLastFrame & 0x01)) @@ -2281,7 +2231,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x07: // Color-Luminance Player 1 + case COLUP1: // Color-Luminance Player 1 { uInt32 color = (uInt32)(value & 0xfe); if(myColorLossEnabled && (myScanlineCountForLastFrame & 0x01)) @@ -2292,7 +2242,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x08: // Color-Luminance Playfield + case COLUPF: // Color-Luminance Playfield { uInt32 color = (uInt32)(value & 0xfe); if(myColorLossEnabled && (myScanlineCountForLastFrame & 0x01)) @@ -2303,7 +2253,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x09: // Color-Luminance Background + case COLUBK: // Color-Luminance Background { uInt32 color = (uInt32)(value & 0xfe); if(myColorLossEnabled && (myScanlineCountForLastFrame & 0x01)) @@ -2314,7 +2264,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x0A: // Control Playfield, Ball size, Collisions + case CTRLPF: // Control Playfield, Ball size, Collisions { myCTRLPF = value; @@ -2336,7 +2286,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x0B: // Reflect Player 0 + case REFP0: // Reflect Player 0 { // See if the reflection state of the player is being changed if(((value & 0x08) && !myREFP0) || (!(value & 0x08) && myREFP0)) @@ -2347,7 +2297,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x0C: // Reflect Player 1 + case REFP1: // Reflect Player 1 { // See if the reflection state of the player is being changed if(((value & 0x08) && !myREFP1) || (!(value & 0x08) && myREFP1)) @@ -2358,7 +2308,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x0D: // Playfield register byte 0 + case PF0: // Playfield register byte 0 { myPF = (myPF & 0x000FFFF0) | ((value >> 4) & 0x0F); @@ -2370,7 +2320,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x0E: // Playfield register byte 1 + case PF1: // Playfield register byte 1 { myPF = (myPF & 0x000FF00F) | ((uInt32)value << 4); @@ -2382,7 +2332,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x0F: // Playfield register byte 2 + case PF2: // Playfield register byte 2 { myPF = (myPF & 0x00000FFF) | ((uInt32)value << 12); @@ -2394,7 +2344,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x10: // Reset Player 0 + case RESP0: // Reset Player 0 { Int32 hpos = (clock - myClockWhenFrameStarted) % 228; Int32 newx = hpos < HBLANK ? 3 : (((hpos - HBLANK) + 5) % 160); @@ -2445,7 +2395,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x11: // Reset Player 1 + case RESP1: // Reset Player 1 { Int32 hpos = (clock - myClockWhenFrameStarted) % 228; Int32 newx = hpos < HBLANK ? 3 : (((hpos - HBLANK) + 5) % 160); @@ -2496,7 +2446,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x12: // Reset Missle 0 + case RESM0: // Reset Missle 0 { int hpos = (clock - myClockWhenFrameStarted) % 228; myPOSM0 = hpos < HBLANK ? 2 : (((hpos - HBLANK) + 4) % 160); @@ -2508,6 +2458,7 @@ void TIA::poke(uInt16 addr, uInt8 value) << " hpos: " << hpos << ", myPOSM0 = " << myPOSM0 << endl; #endif +#ifndef NO_HMOVE_FIXES // TODO: Remove the following special hack for Dolphin by // figuring out what really happens when Reset Missle // occurs 20 cycles after an HMOVE (04/13/02). @@ -2522,13 +2473,13 @@ void TIA::poke(uInt16 addr, uInt8 value) { myPOSM0 = 8; } - +#endif myCurrentM0Mask = &ourMissleMaskTable[myPOSM0 & 0x03] [myNUSIZ0 & 0x07][(myNUSIZ0 & 0x30) >> 4][160 - (myPOSM0 & 0xFC)]; break; } - case 0x13: // Reset Missle 1 + case RESM1: // Reset Missle 1 { int hpos = (clock - myClockWhenFrameStarted) % 228; myPOSM1 = hpos < HBLANK ? 2 : (((hpos - HBLANK) + 4) % 160); @@ -2540,6 +2491,7 @@ void TIA::poke(uInt16 addr, uInt8 value) << " hpos: " << hpos << ", myPOSM1 = " << myPOSM1 << endl; #endif +#ifndef NO_HMOVE_FIXES // TODO: Remove the following special hack for Pitfall II by // figuring out what really happens when Reset Missle // occurs 3 cycles after an HMOVE (04/13/02). @@ -2547,13 +2499,13 @@ void TIA::poke(uInt16 addr, uInt8 value) { myPOSM1 = 3; } - +#endif myCurrentM1Mask = &ourMissleMaskTable[myPOSM1 & 0x03] [myNUSIZ1 & 0x07][(myNUSIZ1 & 0x30) >> 4][160 - (myPOSM1 & 0xFC)]; break; } - case 0x14: // Reset Ball + case RESBL: // Reset Ball { int hpos = (clock - myClockWhenFrameStarted) % 228 ; myPOSBL = hpos < HBLANK ? 2 : (((hpos - HBLANK) + 4) % 160); @@ -2565,6 +2517,7 @@ void TIA::poke(uInt16 addr, uInt8 value) << " hpos: " << hpos << ", myPOSBL = " << myPOSBL << endl; #endif +#ifndef NO_HMOVE_FIXES // TODO: Remove the following special hack by figuring out what // really happens when Reset Ball occurs 18 cycles after an HMOVE. if((clock - myLastHMOVEClock) == (18 * 3)) @@ -2618,55 +2571,55 @@ void TIA::poke(uInt16 addr, uInt8 value) { myPOSBL = 8; } - +#endif myCurrentBLMask = &ourBallMaskTable[myPOSBL & 0x03] [(myCTRLPF & 0x30) >> 4][160 - (myPOSBL & 0xFC)]; break; } - case 0x15: // Audio control 0 + case AUDC0: // Audio control 0 { myAUDC0 = value & 0x0f; mySound->set(addr, value, mySystem->cycles()); break; } - case 0x16: // Audio control 1 + case AUDC1: // Audio control 1 { myAUDC1 = value & 0x0f; mySound->set(addr, value, mySystem->cycles()); break; } - case 0x17: // Audio frequency 0 + case AUDF0: // Audio frequency 0 { myAUDF0 = value & 0x1f; mySound->set(addr, value, mySystem->cycles()); break; } - case 0x18: // Audio frequency 1 + case AUDF1: // Audio frequency 1 { myAUDF1 = value & 0x1f; mySound->set(addr, value, mySystem->cycles()); break; } - case 0x19: // Audio volume 0 + case AUDV0: // Audio volume 0 { myAUDV0 = value & 0x0f; mySound->set(addr, value, mySystem->cycles()); break; } - case 0x1A: // Audio volume 1 + case AUDV1: // Audio volume 1 { myAUDV1 = value & 0x0f; mySound->set(addr, value, mySystem->cycles()); break; } - case 0x1B: // Graphics Player 0 + case GRP0: // Graphics Player 0 { // Set player 0 graphics myGRP0 = (myBitEnabled[TIA::P0] ? value : 0); @@ -2696,7 +2649,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x1C: // Graphics Player 1 + case GRP1: // Graphics Player 1 { // Set player 1 graphics myGRP1 = (myBitEnabled[TIA::P1] ? value : 0); @@ -2734,7 +2687,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x1D: // Enable Missile 0 graphics + case ENAM0: // Enable Missile 0 graphics { myENAM0 = (myBitEnabled[TIA::M0] ? value & 0x02 : 0); @@ -2745,7 +2698,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x1E: // Enable Missile 1 graphics + case ENAM1: // Enable Missile 1 graphics { myENAM1 = (myBitEnabled[TIA::M1] ? value & 0x02 : 0); @@ -2756,7 +2709,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x1F: // Enable Ball graphics + case ENABL: // Enable Ball graphics { myENABL = (myBitEnabled[TIA::BL] ? value & 0x02 : 0); @@ -2768,19 +2721,19 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x20: // Horizontal Motion Player 0 + case HMP0: // Horizontal Motion Player 0 { myHMP0 = value >> 4; break; } - case 0x21: // Horizontal Motion Player 1 + case HMP1: // Horizontal Motion Player 1 { myHMP1 = value >> 4; break; } - case 0x22: // Horizontal Motion Missle 0 + case HMM0: // Horizontal Motion Missle 0 { Int8 tmp = value >> 4; @@ -2795,19 +2748,19 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x23: // Horizontal Motion Missle 1 + case HMM1: // Horizontal Motion Missle 1 { myHMM1 = value >> 4; break; } - case 0x24: // Horizontal Motion Ball + case HMBL: // Horizontal Motion Ball { myHMBL = value >> 4; break; } - case 0x25: // Vertial Delay Player 0 + case VDELP0: // Vertial Delay Player 0 { myVDELP0 = value & 0x01; @@ -2821,7 +2774,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x26: // Vertial Delay Player 1 + case VDELP1: // Vertial Delay Player 1 { myVDELP1 = value & 0x01; @@ -2835,7 +2788,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x27: // Vertial Delay Ball + case VDELBL: // Vertial Delay Ball { myVDELBL = value & 0x01; @@ -2846,7 +2799,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x28: // Reset missle 0 to player 0 + case RESMP0: // Reset missle 0 to player 0 { if(myRESMP0 && !(value & 0x02)) { @@ -2874,7 +2827,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x29: // Reset missle 1 to player 1 + case RESMP1: // Reset missle 1 to player 1 { if(myRESMP1 && !(value & 0x02)) { @@ -2901,7 +2854,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x2A: // Apply horizontal motion + case HMOVE: // Apply horizontal motion { // Figure out what cycle we're at Int32 x = ((clock - myClockWhenFrameStarted) % 228) / 3; @@ -2965,7 +2918,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x2b: // Clear horizontal motion registers + case HMCLR: // Clear horizontal motion registers { myHMP0 = 0; myHMP1 = 0; @@ -2975,7 +2928,7 @@ void TIA::poke(uInt16 addr, uInt8 value) break; } - case 0x2c: // Clear collision latches + case CXCLR: // Clear collision latches { myCollision = 0; break; diff --git a/stella/src/emucore/TIA.hxx b/stella/src/emucore/TIA.hxx index fa82accb6..d29fc30b6 100644 --- a/stella/src/emucore/TIA.hxx +++ b/stella/src/emucore/TIA.hxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: TIA.hxx,v 1.49 2009-01-12 01:07:29 stephena Exp $ +// $Id: TIA.hxx,v 1.50 2009-01-13 01:18:25 stephena Exp $ //============================================================================ #ifndef TIA_HXX @@ -40,7 +40,7 @@ class Settings; be displayed on screen. @author Bradford W. Mott - @version $Id: TIA.hxx,v 1.49 2009-01-12 01:07:29 stephena Exp $ + @version $Id: TIA.hxx,v 1.50 2009-01-13 01:18:25 stephena Exp $ */ class TIA : public Device , public MediaSource { @@ -294,6 +294,9 @@ class TIA : public Device , public MediaSource // Update bookkeeping at end of frame void endFrame(); + // Convert resistance from ports to dumped value + uInt8 dumpedInputPort(int resistance); + private: // Console the TIA is associated with Console& myConsole; @@ -372,26 +375,9 @@ class TIA : public Device , public MediaSource // Indicates the maximum number of scanlines to be generated for a frame Int32 myMaximumNumberOfScanlines; - private: // Color clock when VSYNC ending causes a new frame to be started Int32 myVSYNCFinishClock; - private: - enum - { - myP0Bit = 0x01, // Bit for Player 0 - myM0Bit = 0x02, // Bit for Missle 0 - myP1Bit = 0x04, // Bit for Player 1 - myM1Bit = 0x08, // Bit for Missle 1 - myBLBit = 0x10, // Bit for Ball - myPFBit = 0x20, // Bit for Playfield - ScoreBit = 0x40, // Bit for Playfield score mode - PriorityBit = 0x080 // Bit for Playfield priority - }; - - // Bitmap of the objects that should be considered while drawing - uInt8 myEnabledObjects; - private: uInt8 myVSYNC; // Holds the VSYNC register value uInt8 myVBLANK; // Holds the VBLANK register value @@ -515,6 +501,9 @@ class TIA : public Device , public MediaSource // Counter used for TIA M0 "bug" uInt32 myM0CosmicArkCounter; + // Bitmap of the objects that should be considered while drawing + uInt8 myEnabledObjects; + // Answers whether specified bits (from TIABit) are enabled or disabled bool myBitEnabled[6]; @@ -524,7 +513,85 @@ class TIA : public Device , public MediaSource // Automatic framerate correction based on number of scanlines bool myAutoFrameEnabled; + // The framerate currently in use by the Console + float myFramerate; + private: + enum { // TODO - convert these to match TIA.cs + myP0Bit = 0x01, // Bit for Player 0 + myM0Bit = 0x02, // Bit for Missle 0 + myP1Bit = 0x04, // Bit for Player 1 + myM1Bit = 0x08, // Bit for Missle 1 + myBLBit = 0x10, // Bit for Ball + myPFBit = 0x20, // Bit for Playfield + ScoreBit = 0x40, // Bit for Playfield score mode + PriorityBit = 0x80 // Bit for Playfield priority + }; + + // TIA Write/Read register names + enum { + VSYNC = 0x00, // Write: vertical sync set-clear (D1) + VBLANK = 0x01, // Write: vertical blank set-clear (D7-6,D1) + WSYNC = 0x02, // Write: wait for leading edge of hrz. blank (strobe) + RSYNC = 0x03, // Write: reset hrz. sync counter (strobe) + NUSIZ0 = 0x04, // Write: number-size player-missle 0 (D5-0) + NUSIZ1 = 0x05, // Write: number-size player-missle 1 (D5-0) + COLUP0 = 0x06, // Write: color-lum player 0 (D7-1) + COLUP1 = 0x07, // Write: color-lum player 1 (D7-1) + COLUPF = 0x08, // Write: color-lum playfield (D7-1) + COLUBK = 0x09, // Write: color-lum background (D7-1) + CTRLPF = 0x0a, // Write: cntrl playfield ballsize & coll. (D5-4,D2-0) + REFP0 = 0x0b, // Write: reflect player 0 (D3) + REFP1 = 0x0c, // Write: reflect player 1 (D3) + PF0 = 0x0d, // Write: playfield register byte 0 (D7-4) + PF1 = 0x0e, // Write: playfield register byte 1 (D7-0) + PF2 = 0x0f, // Write: playfield register byte 2 (D7-0) + RESP0 = 0x10, // Write: reset player 0 (strobe) + RESP1 = 0x11, // Write: reset player 1 (strobe) + RESM0 = 0x12, // Write: reset missle 0 (strobe) + RESM1 = 0x13, // Write: reset missle 1 (strobe) + RESBL = 0x14, // Write: reset ball (strobe) + AUDC0 = 0x15, // Write: audio control 0 (D3-0) + AUDC1 = 0x16, // Write: audio control 1 (D4-0) + AUDF0 = 0x17, // Write: audio frequency 0 (D4-0) + AUDF1 = 0x18, // Write: audio frequency 1 (D3-0) + AUDV0 = 0x19, // Write: audio volume 0 (D3-0) + AUDV1 = 0x1a, // Write: audio volume 1 (D3-0) + GRP0 = 0x1b, // Write: graphics player 0 (D7-0) + GRP1 = 0x1c, // Write: graphics player 1 (D7-0) + ENAM0 = 0x1d, // Write: graphics (enable) missle 0 (D1) + ENAM1 = 0x1e, // Write: graphics (enable) missle 1 (D1) + ENABL = 0x1f, // Write: graphics (enable) ball (D1) + HMP0 = 0x20, // Write: horizontal motion player 0 (D7-4) + HMP1 = 0x21, // Write: horizontal motion player 1 (D7-4) + HMM0 = 0x22, // Write: horizontal motion missle 0 (D7-4) + HMM1 = 0x23, // Write: horizontal motion missle 1 (D7-4) + HMBL = 0x24, // Write: horizontal motion ball (D7-4) + VDELP0 = 0x25, // Write: vertical delay player 0 (D0) + VDELP1 = 0x26, // Write: vertical delay player 1 (D0) + VDELBL = 0x27, // Write: vertical delay ball (D0) + RESMP0 = 0x28, // Write: reset missle 0 to player 0 (D1) + RESMP1 = 0x29, // Write: reset missle 1 to player 1 (D1) + HMOVE = 0x2a, // Write: apply horizontal motion (strobe) + HMCLR = 0x2b, // Write: clear horizontal motion registers (strobe) + CXCLR = 0x2c, // Write: clear collision latches (strobe) + + CXM0P = 0x00, // Read collision: D7=(M0,P1); D6=(M0,P0) + CXM1P = 0x01, // Read collision: D7=(M1,P0); D6=(M1,P1) + CXP0FB = 0x02, // Read collision: D7=(P0,PF); D6=(P0,BL) + CXP1FB = 0x03, // Read collision: D7=(P1,PF); D6=(P1,BL) + CXM0FB = 0x04, // Read collision: D7=(M0,PF); D6=(M0,BL) + CXM1FB = 0x05, // Read collision: D7=(M1,PF); D6=(M1,BL) + CXBLPF = 0x06, // Read collision: D7=(BL,PF); D6=(unused) + CXPPMM = 0x07, // Read collision: D7=(P0,P1); D6=(M0,M1) + INPT0 = 0x08, // Read pot port: D7 + INPT1 = 0x09, // Read pot port: D7 + INPT2 = 0x0a, // Read pot port: D7 + INPT3 = 0x0b, // Read pot port: D7 + INPT4 = 0x0c, // Read P1 joystick trigger: D7 + INPT5 = 0x0d // Read P2 joystick trigger: D7 + }; + // Ball mask table (entries are true or false) static uInt8 ourBallMaskTable[4][4][320];