File: TIA.hxx

package info (click to toggle)
stella 0.7-2
  • links: PTS
  • area: non-free
  • in suites: hamm, slink
  • size: 864 kB
  • ctags: 1,158
  • sloc: cpp: 6,615; ansic: 492; makefile: 224; asm: 31
file content (283 lines) | stat: -rw-r--r-- 9,475 bytes parent folder | download
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