1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
|
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa "An Atari 2600 VCS Emulator"
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa Copyright (c) 1995,1996,1997
// SS SS tt ee ll ll aa aa Bradford W. Mott
// SSSS ttt eeeee llll llll aaaaa
//
//============================================================================
#ifndef TIA_HXX
#define TIA_HXX
class System;
class Sound;
#include "machine.hxx"
#include "Device.hxx"
/**
A device that emulates the Television Interface Adapator found in
the Atari 2600. The Television Interface Adapator is an integrated
circuit designed to interface between an eight bit microprocessor
and a television video modulator. It converts eight bit parallel data
into serial outputs for the color, luminosity, and composite sync
required by a video modulator.
This class emulates the TIA by outputing the serial outputs into
a frame buffer which can then be displayed on screen.
@author Bradford W. Mott
@version $Id: TIA.hxx,v 1.2 1997/05/17 19:00:09 bwmott Exp $
*/
class TIA : public Device
{
public:
/// Constructor
TIA(System& system);
/// Destructor
virtual ~TIA();
public:
/// Answer byte at the specified address
virtual uByte peek(uWord addr);
/// Write value at the specified address.
virtual void poke(uWord addr, uByte value);
/// Reset to power on state
virtual void reset();
public:
/// Execute instructions until the next frame has been generated
void frame(bool drawFrame = true);
/// Answer pointer to the current frame buffer
uByte* currentFrameBuffer() { return myCurrentFrameBuffer; }
/// Answer pointer to the previous frame buffer (for delta updating)
uByte* previousFrameBuffer() { return myPreviousFrameBuffer; }
/// Answer the height of my frame buffer
uWord height() const;
/// Answer the width of my frame buffer
uWord width() const { return 160; }
public:
/// Answer sound object used for playing audio
Sound& sound() const;
private:
// Compute the ball mask table
void computeBallMaskTable();
// Compute the collision decode table
void computeCollisionTable();
// Compute the missle mask table
void computeMissleMaskTable();
// Compute the player mask table
void computePlayerMaskTable();
// Compute the player reflect table
void computePlayerReflectTable();
// Compute playfield mask table
void computePlayfieldMaskTable();
private:
// Helper function for the updateFrame method
void updateFrameHelper(uLong clock);
// Update the current frame buffer to the specified color clock
void updateFrame(uLong clock);
// Waste CPU cycles until the current scanline is finished
void waitHorizontalSync();
private:
// Pointer to my sound object
Sound* mySound;
private:
// Pointer to the current frame buffer
uByte* myCurrentFrameBuffer;
// Pointer to the previous frame buffer
uByte* myPreviousFrameBuffer;
// Pointer to the next pixel that will be drawn in the current frame buffer
uByte* myFramePointer;
// Indicates whether the frame should be drawn or not
bool myDrawFrame;
private:
// Indicates offset in color clocks when display should begin
uLong myStartDisplayOffset;
// Indicates offset in color clocks when display should stop
uLong myStopDisplayOffset;
private:
// Indicates color clocks when the current frame began
uLong myClockWhenFrameStarted;
// Indicates color clocks when frame should begin to be drawn
uLong myClockStartDisplay;
// Indicates color clocks when frame should stop being drawn
uLong myClockStopDisplay;
// Indicates color clocks when the frame was last updated
uLong myClockAtLastUpdate;
// Indicates how many color clocks remain until the end of
// current scanline. This value is valid during the
// displayed portion of the frame.
uLong myClockToEndOfScanLine;
private:
// Color clock when VSYNC ending causes a new frame to be started
uLong myVSYNCFinishClock;
// Number of color clocks to delay a player's graphics write by
uLong myPlayerDelay;
private:
const uByte myP0Bit = 0x01; // Bit for Player 0
const uByte myM0Bit = 0x02; // Bit for Missle 0
const uByte myP1Bit = 0x04; // Bit for Player 1
const uByte myM1Bit = 0x08; // Bit for Missle 1
const uByte myBLBit = 0x10; // Bit for Ball
const uByte myPFBit = 0x20; // Bit for Playfield
// Bitmap of the objects that should be considered while drawing
uByte myEnabledObjects;
private:
uByte myVSYNC; // Holds the VSYNC register value
uByte myVBLANK; // Holds the VBLANK register value
uByte myNUSIZ0; // Number and size of player 0 and missle 0
uByte myNUSIZ1; // Number and size of player 1 and missle 1
uLong myCOLUP0; // Player 0 color register (replicated 4 times)
uLong myCOLUP1; // Player 1 color register (replicated 4 times)
uLong myCOLUPF; // Playfield color register (replicated 4 times)
uLong myCOLUBK; // Background color register (replicated 4 times)
uByte myCTRLPF; // Playfield control register
bool myREFP0; // Indicates if player 0 is being reflected
bool myREFP1; // Indicates if player 1 is being reflected
uLong myPF; // Playfield graphics (19-12:PF2 11-4:PF1 3-0:PF0)
uByte myGRP0; // Player 0 graphics register
uByte myGRP1; // Player 1 graphics register
uByte myDGRP0; // Player 0 delayed graphics register
uByte myDGRP1; // Player 1 delayed graphics register
bool myENAM0; // Indicates if missle 0 is enabled
bool myENAM1; // Indicates if missle 0 is enabled
bool myENABL; // Indicates if the ball is enabled
bool myDENABL; // Indicates if the virtically delayed ball is enabled
Byte myHMP0; // Player 0 horizontal motion register
Byte myHMP1; // Player 1 horizontal motion register
Byte myHMM0; // Missle 0 horizontal motion register
Byte myHMM1; // Missle 1 horizontal motion register
Byte myHMBL; // Ball horizontal motion register
bool myVDELP0; // Indicates if player 0 is being virtically delayed
bool myVDELP1; // Indicates if player 1 is being virtically delayed
bool myVDELBL; // Indicates if the ball is being virtically delayed
bool myRESMP0; // Indicates if missle 0 is reset to player 0
bool myRESMP1; // Indicates if missle 1 is reset to player 1
uWord myCollision; // Collision register
// Note that these position registers contain the color clock
// on which the object's serial output should begin (0 to 159)
Word myPOSP0; // Player 0 position register
Word myPOSP1; // Player 1 position register
Word myPOSM0; // Missle 0 position register
Word myPOSM1; // Missle 1 position register
Word myPOSBL; // Ball position register
private:
// Graphics for Player 0 that should be displayed. This will be
// reflected if the player is being reflected.
uByte myCurrentGRP0;
// Graphics for Player 1 that should be displayed. This will be
// reflected if the player is being reflected.
uByte myCurrentGRP1;
// It's VERY important that the BL, M0, M1, P0 and P1 current
// mask pointers are always on a uLong boundary. Otherwise,
// the TIA code will fail on a good number of CPUs.
// Pointer to the currently active mask array for the ball
uByte* myCurrentBLMask;
// Pointer to the currently active mask array for missle 0
uByte* myCurrentM0Mask;
// Pointer to the currently active mask array for missle 1
uByte* myCurrentM1Mask;
// Pointer to the currently active mask array for player 0
uByte* myCurrentP0Mask;
// Pointer to the currently active mask array for player 1
uByte* myCurrentP1Mask;
// Pointer to the currently active mask array for the playfield
uLong* myCurrentPFMask;
// Current value of the playfield register
uLong myCurrentPF;
private:
// Color clock when last HMOVE occured
uLong myLastHMOVEClock;
// TIA M0 "bug" used for stars in Cosmic Ark flag
bool myM0CosmicArkMotionEnabled;
private:
// Ball mask table (entries are true or false)
static uByte ourBallMaskTable[4][4][320];
// Used to set the collision register to the correct value
static uWord ourCollisionTable[64];
// Missle mask table (entries are true or false)
static uByte ourMissleMaskTable[4][8][4][320];
// Used to convert value written in a motion register into
// its internal representation
static Byte ourMotionTable[16];
// Player mask table
static uByte ourPlayerMaskTable[4][8][320];
// Used to reflect a players graphics
static uByte ourPlayerReflectTable[256];
// Playfield mask table for reflected and non-reflected playfields
static uLong ourPlayfieldTable[2][160];
};
#endif
|