K, now that release 2.7 is out of the way, I can move on again.

First pass at cleaning up the TIA class, in anticipation of the new
TIA infrastructure with improved HMOVE emulation.  This code has been
in need of a cleanup for some time now; there are commented TODO's
and FIXME's that are up to 10 years old!

Moved all static constants and tables into a separate TIATables class,
making the main TIA class much shorter and easier to understand.

TIA no longer uses or honours the 'Allow HMOVE blanks' ROM property;
further work will remove this from the codebase entirely.

Removed MediaSource abstraction and have the codebase use the TIA
directly.  It was probably a good idea to have this abstraction when
Stella was first written (in anticipation of multiple TIA
implementations), but seeing how that hasn't happened for approx.
13 years, I don't see it ever happening :)  Besides, we're paying a
price for that abstraction (certain functions can't be inline'd) for
no real reason.  Perhaps in the future, the M6502/M6502Low/M6502Hi
will experience a similar contraction.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1640 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2009-01-19 16:52:32 +00:00
parent 64594bb252
commit a9cb1308b2
27 changed files with 1274 additions and 1454 deletions

View File

@ -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: FrameBufferGL.cxx,v 1.133 2009-01-10 18:42:49 stephena Exp $
// $Id: FrameBufferGL.cxx,v 1.134 2009-01-19 16:52:32 stephena Exp $
//============================================================================
#ifdef DISPLAY_OPENGL
@ -26,10 +26,10 @@
#include "Console.hxx"
#include "Font.hxx"
#include "MediaSrc.hxx"
#include "OSystem.hxx"
#include "Settings.hxx"
#include "Surface.hxx"
#include "TIA.hxx"
#include "FrameBufferGL.hxx"
@ -354,15 +354,15 @@ cerr << "dimensions: " << (fullScreen() ? "(full)" : "") << endl
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferGL::drawMediaSource(bool fullRedraw)
void FrameBufferGL::drawTIA(bool fullRedraw)
{
MediaSource& mediasrc = myOSystem->console().mediaSource();
const TIA& tia = myOSystem->console().tia();
// Copy the mediasource framebuffer to the RGB texture
uInt8* currentFrame = mediasrc.currentFrameBuffer();
uInt8* previousFrame = mediasrc.previousFrameBuffer();
uInt32 width = mediasrc.width();
uInt32 height = mediasrc.height();
uInt8* currentFrame = tia.currentFrameBuffer();
uInt8* previousFrame = tia.previousFrameBuffer();
uInt32 width = tia.width();
uInt32 height = tia.height();
uInt32 pitch = myTiaSurface->pitch();
uInt16* buffer = (uInt16*) myTiaSurface->pixels();

View File

@ -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: FrameBufferGL.hxx,v 1.71 2009-01-15 23:07:29 stephena Exp $
// $Id: FrameBufferGL.hxx,v 1.72 2009-01-19 16:52:32 stephena Exp $
//============================================================================
#ifndef FRAMEBUFFER_GL_HXX
@ -35,7 +35,7 @@ class FBSurfaceGL;
This class implements an SDL OpenGL framebuffer.
@author Stephen Anthony
@version $Id: FrameBufferGL.hxx,v 1.71 2009-01-15 23:07:29 stephena Exp $
@version $Id: FrameBufferGL.hxx,v 1.72 2009-01-19 16:52:32 stephena Exp $
*/
class FrameBufferGL : public FrameBuffer
{
@ -138,10 +138,10 @@ class FrameBufferGL : public FrameBuffer
FBSurface* createSurface(int w, int h, bool useBase = false) const;
/**
This method should be called anytime the MediaSource needs to be redrawn
This method should be called anytime the TIA needs to be redrawn
to the screen (full indicating that a full redraw is required).
*/
void drawMediaSource(bool full);
void drawTIA(bool full);
/**
This method is called to provide information about the FrameBuffer.
@ -187,7 +187,7 @@ class FrameBufferGL : public FrameBuffer
A surface suitable for OpenGL rendering mode.
@author Stephen Anthony
@version $Id: FrameBufferGL.hxx,v 1.71 2009-01-15 23:07:29 stephena Exp $
@version $Id: FrameBufferGL.hxx,v 1.72 2009-01-19 16:52:32 stephena Exp $
*/
class FBSurfaceGL : public FBSurface
{

View File

@ -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: FrameBufferSoft.cxx,v 1.93 2009-01-14 20:31:07 stephena Exp $
// $Id: FrameBufferSoft.cxx,v 1.94 2009-01-19 16:52:32 stephena Exp $
//============================================================================
#include <sstream>
@ -23,11 +23,11 @@
#include "Console.hxx"
#include "Font.hxx"
#include "MediaSrc.hxx"
#include "OSystem.hxx"
#include "RectList.hxx"
#include "Settings.hxx"
#include "Surface.hxx"
#include "TIA.hxx"
#include "FrameBufferSoft.hxx"
@ -102,7 +102,7 @@ bool FrameBufferSoft::setVidMode(VideoMode& mode)
myFormat = myScreen->format;
myBytesPerPixel = myFormat->BytesPerPixel;
// Make sure drawMediaSource() knows which renderer to use
// Make sure drawTIA() knows which renderer to use
switch(myBytesPerPixel)
{
case 2: // 16-bit
@ -136,15 +136,15 @@ bool FrameBufferSoft::setVidMode(VideoMode& mode)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSoft::drawMediaSource(bool fullRedraw)
void FrameBufferSoft::drawTIA(bool fullRedraw)
{
MediaSource& mediasrc = myOSystem->console().mediaSource();
const TIA& tia = myOSystem->console().tia();
uInt8* currentFrame = mediasrc.currentFrameBuffer();
uInt8* previousFrame = mediasrc.previousFrameBuffer();
uInt8* currentFrame = tia.currentFrameBuffer();
uInt8* previousFrame = tia.previousFrameBuffer();
uInt32 width = mediasrc.width();
uInt32 height = mediasrc.height();
uInt32 width = tia.width();
uInt32 height = tia.height();
switch(myRenderType)
{

View File

@ -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: FrameBufferSoft.hxx,v 1.64 2009-01-10 18:52:55 stephena Exp $
// $Id: FrameBufferSoft.hxx,v 1.65 2009-01-19 16:52:32 stephena Exp $
//============================================================================
#ifndef FRAMEBUFFER_SOFT_HXX
@ -32,7 +32,7 @@ class RectList;
This class implements an SDL software framebuffer.
@author Stephen Anthony
@version $Id: FrameBufferSoft.hxx,v 1.64 2009-01-10 18:52:55 stephena Exp $
@version $Id: FrameBufferSoft.hxx,v 1.65 2009-01-19 16:52:32 stephena Exp $
*/
class FrameBufferSoft : public FrameBuffer
{
@ -126,10 +126,10 @@ class FrameBufferSoft : public FrameBuffer
FBSurface* createSurface(int w, int h, bool useBase = false) const;
/**
This method should be called anytime the MediaSource needs to be redrawn
This method should be called anytime the TIA needs to be redrawn
to the screen (full indicating that a full redraw is required).
*/
void drawMediaSource(bool full);
void drawTIA(bool full);
/**
This method is called after any drawing is done (per-frame).
@ -172,7 +172,7 @@ class FrameBufferSoft : public FrameBuffer
A surface suitable for software rendering mode.
@author Stephen Anthony
@version $Id: FrameBufferSoft.hxx,v 1.64 2009-01-10 18:52:55 stephena Exp $
@version $Id: FrameBufferSoft.hxx,v 1.65 2009-01-19 16:52:32 stephena Exp $
*/
class FBSurfaceSoft : public FBSurface
{

View File

@ -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: Snapshot.cxx,v 1.26 2009-01-11 02:23:45 stephena Exp $
// $Id: Snapshot.cxx,v 1.27 2009-01-19 16:52:32 stephena Exp $
//============================================================================
#include <zlib.h>
@ -23,8 +23,8 @@
#include "bspf.hxx"
#include "FrameBuffer.hxx"
#include "MediaSrc.hxx"
#include "Props.hxx"
#include "TIA.hxx"
#include "Version.hxx"
#include "Snapshot.hxx"
@ -56,15 +56,14 @@ string Snapshot::savePNG(const FrameBuffer& framebuffer, const Properties& props
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string Snapshot::savePNG(const FrameBuffer& framebuffer,
const MediaSource& mediasrc, const Properties& props,
const string& filename)
string Snapshot::savePNG(const FrameBuffer& framebuffer, const TIA& tia,
const Properties& props, const string& filename)
{
ofstream out(filename.c_str(), ios_base::binary);
if(!out.is_open())
return "ERROR: Couldn't create snapshot file";
uInt32 width = mediasrc.width(), height = mediasrc.height();
uInt32 width = tia.width(), height = tia.height();
uInt8* buffer = new uInt8[(width*3*2 + 1) * height];
// Fill the buffer with pixels from the mediasrc

View File

@ -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: Snapshot.hxx,v 1.15 2009-01-03 22:57:12 stephena Exp $
// $Id: Snapshot.hxx,v 1.16 2009-01-19 16:52:32 stephena Exp $
//============================================================================
#ifndef SNAPSHOT_HXX
@ -21,7 +21,7 @@
class Properties;
class FrameBuffer;
class MediaSource;
class TIA;
#include <fstream>
#include "bspf.hxx"
@ -42,16 +42,15 @@ class Snapshot
/**
Save the current TIA image to a PNG file using data directly from
the MediaSource/TIA. No filtering or scaling will be included.
the TIA framebuffer. No filtering or scaling will be included.
@param framebuffer The framebuffer containing the image data
@param mediasrc Source of the raw TIA data
@param props The properties object containing info about the ROM
@param filename The filename of the PNG file
*/
static string savePNG(const FrameBuffer& framebuffer,
const MediaSource& mediasrc, const Properties& props,
const string& filename);
static string savePNG(const FrameBuffer& framebuffer, const TIA& tia,
const Properties& props, const string& filename);
private:
static string saveBufferToPNG(ofstream& out, uInt8* buffer,

View File

@ -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: SoundSDL.hxx,v 1.21 2009-01-01 18:13:35 stephena Exp $
// $Id: SoundSDL.hxx,v 1.22 2009-01-19 16:52:32 stephena Exp $
//============================================================================
#ifndef SOUND_SDL_HXX
@ -25,16 +25,15 @@ class OSystem;
#include <SDL.h>
#include "Sound.hxx"
#include "bspf.hxx"
#include "MediaSrc.hxx"
#include "TIASnd.hxx"
#include "Sound.hxx"
/**
This class implements the sound API for SDL.
@author Stephen Anthony and Bradford W. Mott
@version $Id: SoundSDL.hxx,v 1.21 2009-01-01 18:13:35 stephena Exp $
@version $Id: SoundSDL.hxx,v 1.22 2009-01-19 16:52:32 stephena Exp $
*/
class SoundSDL : public Sound
{

View File

@ -13,13 +13,13 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Version.hxx,v 1.45 2009-01-16 19:10:06 stephena Exp $
// $Id: Version.hxx,v 1.46 2009-01-19 16:52:32 stephena Exp $
//============================================================================
#ifndef VERSION_HXX
#define VERSION_HXX
#define STELLA_BASE_VERSION "2.7"
#define STELLA_BASE_VERSION "2.7.1_cvs"
#ifdef NIGHTLY_BUILD
#define STELLA_VERSION STELLA_BASE_VERSION "pre-" NIGHTLY_BUILD

View File

@ -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: Debugger.cxx,v 1.132 2009-01-15 21:04:47 stephena Exp $
// $Id: Debugger.cxx,v 1.133 2009-01-19 16:52:32 stephena Exp $
//============================================================================
#include "bspf.hxx"
@ -466,7 +466,7 @@ int Debugger::step()
int cyc = mySystem->cycles();
unlockState();
myOSystem->console().mediaSource().updateScanlineByStep();
myOSystem->console().tia().updateScanlineByStep();
lockState();
return mySystem->cycles() - cyc;
@ -494,7 +494,7 @@ int Debugger::trace()
int targetPC = myCpuDebug->pc() + 3; // return address
unlockState();
myOSystem->console().mediaSource().updateScanlineByTrace(targetPC);
myOSystem->console().tia().updateScanlineByTrace(targetPC);
lockState();
return mySystem->cycles() - cyc;

View File

@ -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: TIADebug.cxx,v 1.29 2009-01-03 22:57:12 stephena Exp $
// $Id: TIADebug.cxx,v 1.30 2009-01-19 16:52:32 stephena Exp $
//============================================================================
#include "System.hxx"
@ -24,7 +24,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TIADebug::TIADebug(Debugger& dbg, Console& console)
: DebuggerSystem(dbg, console),
myTIA((TIA&)console.mediaSource())
myTIA(console.tia())
{
nusizStrings[0] = "size=8 copy=1";
nusizStrings[1] = "size=8 copy=2 spac=8";

View File

@ -13,18 +13,18 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: TIADebug.hxx,v 1.25 2009-01-12 15:11:54 stephena Exp $
// $Id: TIADebug.hxx,v 1.26 2009-01-19 16:52:32 stephena Exp $
//============================================================================
#ifndef TIA_DEBUG_HXX
#define TIA_DEBUG_HXX
class TIA;
class Debugger;
class TiaDebug;
#include "Array.hxx"
#include "DebuggerSystem.hxx"
#include "TIA.hxx"
// pointer types for TIADebug instance methods
// (used by TiaMethodExpression)

View File

@ -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: TiaOutputWidget.cxx,v 1.25 2009-01-11 02:23:45 stephena Exp $
// $Id: TiaOutputWidget.cxx,v 1.26 2009-01-19 16:52:32 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -68,7 +68,7 @@ void TiaOutputWidget::advanceScanline(int lines)
{
while(lines)
{
instance().console().mediaSource().updateScanline();
instance().console().tia().updateScanline();
--lines;
}
}
@ -78,7 +78,7 @@ void TiaOutputWidget::advance(int frames)
{
while(frames)
{
instance().console().mediaSource().update();
instance().console().tia().update();
--frames;
}
}
@ -144,7 +144,7 @@ void TiaOutputWidget::drawWidget(bool hilite)
FBSurface& s = dialog().surface();
const uInt32 width = 160, // width is always 160
height = instance().console().mediaSource().height();
height = instance().console().tia().height();
for(uInt32 y = 0; y < height; ++y)
{
uInt32* line_ptr = myLineBuffer;

View File

@ -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: TiaZoomWidget.cxx,v 1.22 2009-01-03 22:57:12 stephena Exp $
// $Id: TiaZoomWidget.cxx,v 1.23 2009-01-19 16:52:32 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -104,8 +104,8 @@ void TiaZoomWidget::zoom(int level)
void TiaZoomWidget::recalc()
{
// Don't go past end of framebuffer
const int width = instance().console().mediaSource().width(),
height = instance().console().mediaSource().height();
const int width = instance().console().tia().width(),
height = instance().console().tia().height();
// Figure out the bounding rectangle for the current center coords
const int xoff = myNumCols >> 1,
@ -220,8 +220,8 @@ void TiaZoomWidget::drawWidget(bool hilite)
// Draw the zoomed image
// This probably isn't as efficient as it can be, but it's a small area
// and I don't have time to make it faster :)
uInt8* currentFrame = instance().console().mediaSource().currentFrameBuffer();
const int pitch = instance().console().mediaSource().width(),
uInt8* currentFrame = instance().console().tia().currentFrameBuffer();
const int pitch = instance().console().tia().width(),
width = myZoomLevel << 1,
height = myZoomLevel;

View File

@ -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: Console.cxx,v 1.151 2009-01-01 18:13:35 stephena Exp $
// $Id: Console.cxx,v 1.152 2009-01-19 16:52:32 stephena Exp $
//============================================================================
#include <cassert>
@ -34,7 +34,6 @@
#include "M6502Hi.hxx"
#include "M6502Low.hxx"
#include "M6532.hxx"
#include "MediaSrc.hxx"
#include "Paddles.hxx"
#include "Props.hxx"
#include "PropsSet.hxx"
@ -71,7 +70,7 @@ Console::Console(OSystem* osystem, Cartridge* cart, const Properties& props)
{
myControllers[0] = 0;
myControllers[1] = 0;
myMediaSource = 0;
myTIA = 0;
mySwitches = 0;
mySystem = 0;
myEvent = 0;
@ -107,19 +106,15 @@ Console::Console(OSystem* osystem, Cartridge* cart, const Properties& props)
m6502->attach(myOSystem->debugger());
#endif
M6532* m6532 = new M6532(*this);
TIA *tia = new TIA(*this, myOSystem->settings());
tia->setSound(myOSystem->sound());
myCart = cart;
myRiot = new M6532(*this);
myTIA = new TIA(*this, myOSystem->settings());
myTIA->setSound(myOSystem->sound());
mySystem->attach(m6502);
mySystem->attach(m6532);
mySystem->attach(tia);
mySystem->attach(cart);
// Remember what my media source is
myMediaSource = tia;
myCart = cart;
myRiot = m6532;
mySystem->attach(myRiot);
mySystem->attach(myTIA);
mySystem->attach(myCart);
// Query some info about this console
ostringstream about, vidinfo;
@ -138,8 +133,8 @@ Console::Console(OSystem* osystem, Cartridge* cart, const Properties& props)
int palCount = 0;
for(int i = 0; i < 60; ++i)
{
myMediaSource->update();
if(i >= 30 && myMediaSource->scanlines() > 285)
myTIA->update();
if(i >= 30 && myTIA->scanlines() > 285)
++palCount;
}
myDisplayFormat = (palCount >= 15) ? "PAL" : "NTSC";
@ -429,7 +424,7 @@ bool Console::initializeVideo(bool full)
string title = string("Stella ") + STELLA_VERSION +
": \"" + myProperties.get(Cartridge_Name) + "\"";
if(!myOSystem->frameBuffer().initialize(title,
myMediaSource->width() << 1, myMediaSource->height()))
myTIA->width() << 1, myTIA->height()))
return false;
myOSystem->frameBuffer().showFrameStats(
@ -451,7 +446,7 @@ bool Console::initializeVideo(bool full)
myOSystem->setFramerate(myFramerate);
// Make sure auto-frame calculation is only enabled when necessary
myMediaSource->enableAutoFrame(framerate <= 0);
myTIA->enableAutoFrame(framerate <= 0);
return true;
}
@ -473,7 +468,7 @@ void Console::initializeAudio()
myOSystem->sound().initialize();
// Make sure auto-frame calculation is only enabled when necessary
myMediaSource->enableAutoFrame(framerate <= 0);
myTIA->enableAutoFrame(framerate <= 0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -532,7 +527,7 @@ void Console::changeYStart(int direction)
strval << ystart;
myProperties.set(Display_YStart, strval.str());
((TIA*)myMediaSource)->frameReset();
myTIA->frameReset();
myOSystem->frameBuffer().refresh();
message = "YStart ";
@ -570,7 +565,7 @@ void Console::changeHeight(int direction)
strval << height;
myProperties.set(Display_Height, strval.str());
((TIA*)myMediaSource)->frameReset();
myTIA->frameReset();
initializeVideo(); // takes care of refreshing the screen
message = "Height ";
@ -696,7 +691,7 @@ void Console::setControllers()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Console::toggleTIABit(TIA::TIABit bit, const string& bitname, bool show) const
{
bool result = ((TIA*)myMediaSource)->toggleBit(bit);
bool result = myTIA->toggleBit(bit);
string message = bitname + (result ? " enabled" : " disabled");
myOSystem->frameBuffer().showMessage(message);
}
@ -704,7 +699,7 @@ void Console::toggleTIABit(TIA::TIABit bit, const string& bitname, bool show) co
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Console::enableBits(bool enable) const
{
((TIA*)myMediaSource)->enableBits(enable);
myTIA->enableBits(enable);
string message = string("TIA bits") + (enable ? " enabled" : " disabled");
myOSystem->frameBuffer().showMessage(message);
}

View File

@ -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: Console.hxx,v 1.71 2009-01-01 18:13:35 stephena Exp $
// $Id: Console.hxx,v 1.72 2009-01-19 16:52:32 stephena Exp $
//============================================================================
#ifndef CONSOLE_HXX
@ -22,9 +22,9 @@
class Console;
class Controller;
class Event;
class MediaSource;
class Switches;
class System;
class TIA;
#include "bspf.hxx"
#include "Control.hxx"
@ -52,7 +52,7 @@ struct ConsoleInfo
This class represents the entire game console.
@author Bradford W. Mott
@version $Id: Console.hxx,v 1.71 2009-01-01 18:13:35 stephena Exp $
@version $Id: Console.hxx,v 1.72 2009-01-19 16:52:32 stephena Exp $
*/
class Console : public Serializable
{
@ -91,11 +91,11 @@ class Console : public Serializable
}
/**
Get the MediaSource for this console
Get the TIA for this console
@return The mediasource
@return The TIA
*/
MediaSource& mediaSource() const { return *myMediaSource; }
TIA& tia() const { return *myTIA; }
/**
Get the properties being used by the game
@ -302,8 +302,8 @@ class Console : public Serializable
// Pointer to the event object to use
Event* myEvent;
// Pointer to the media source object
MediaSource* myMediaSource;
// Pointer to the TIA object
TIA* myTIA;
// Properties for the game
Properties myProperties;

View File

@ -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: EventHandler.cxx,v 1.239 2009-01-16 16:38:06 stephena Exp $
// $Id: EventHandler.cxx,v 1.240 2009-01-19 16:52:32 stephena Exp $
//============================================================================
#include <sstream>
@ -1804,7 +1804,7 @@ void EventHandler::takeSnapshot()
if(myOSystem->settings().getBool("ss1x"))
{
string msg = Snapshot::savePNG(myOSystem->frameBuffer(),
myOSystem->console().mediaSource(),
myOSystem->console().tia(),
myOSystem->console().properties(), filename);
myOSystem->frameBuffer().showMessage(msg);
}

View File

@ -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: FrameBuffer.cxx,v 1.161 2009-01-15 01:31:26 stephena Exp $
// $Id: FrameBuffer.cxx,v 1.162 2009-01-19 16:52:32 stephena Exp $
//============================================================================
#include <algorithm>
@ -27,10 +27,10 @@
#include "Event.hxx"
#include "Font.hxx"
#include "Launcher.hxx"
#include "MediaSrc.hxx"
#include "Menu.hxx"
#include "OSystem.hxx"
#include "Settings.hxx"
#include "TIA.hxx"
#include "FrameBuffer.hxx"
@ -164,7 +164,7 @@ void FrameBuffer::update()
// Run the console for one frame
// Note that the debugger can cause a breakpoint to occur, which changes
// the EventHandler state 'behind our back' - we need to check for that
myOSystem->console().mediaSource().update();
myOSystem->console().tia().update();
#ifdef DEBUGGER_SUPPORT
if(myOSystem->eventHandler().state() != EventHandler::S_EMULATE) break;
#endif
@ -172,7 +172,7 @@ void FrameBuffer::update()
myOSystem->console().fry();
// And update the screen
drawMediaSource(myRedrawEntireFrame);
drawTIA(myRedrawEntireFrame);
// Show frame statistics
if(myStatsMsg.enabled)
@ -180,7 +180,7 @@ void FrameBuffer::update()
const ConsoleInfo& info = myOSystem->console().about();
char msg[30];
sprintf(msg, "%u LINES %2.2f FPS",
myOSystem->console().mediaSource().scanlines(),
myOSystem->console().tia().scanlines(),
myOSystem->console().getFramerate());
myStatsMsg.surface->fillRect(0, 0, myStatsMsg.w, myStatsMsg.h, kBGColor);
myStatsMsg.surface->drawString(&myOSystem->consoleFont(),
@ -200,7 +200,7 @@ void FrameBuffer::update()
{
// Only update the screen if it's been invalidated
if(myRedrawEntireFrame)
drawMediaSource(true);
drawTIA(true);
// Show a pause message every 5 seconds
if(myPausedCount++ >= 7*myOSystem->frameRate())
@ -410,29 +410,29 @@ void FrameBuffer::refresh()
{
case EventHandler::S_EMULATE:
case EventHandler::S_PAUSE:
drawMediaSource(true);
drawTIA(true);
if(doubleBuffered)
drawMediaSource(true);
drawTIA(true);
break;
case EventHandler::S_MENU:
drawMediaSource(true);
drawTIA(true);
myOSystem->menu().draw(true);
if(doubleBuffered)
{
postFrameUpdate();
drawMediaSource(true);
drawTIA(true);
myOSystem->menu().draw(true);
}
break;
case EventHandler::S_CMDMENU:
drawMediaSource(true);
drawTIA(true);
myOSystem->commandMenu().draw(true);
if(doubleBuffered)
{
postFrameUpdate();
drawMediaSource(true);
drawTIA(true);
myOSystem->commandMenu().draw(true);
}
break;
@ -502,8 +502,8 @@ void FrameBuffer::resetSurfaces()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 FrameBuffer::tiaPixel(uInt32 idx) const
{
uInt8 c = *(myOSystem->console().mediaSource().currentFrameBuffer() + idx);
uInt8 p = *(myOSystem->console().mediaSource().previousFrameBuffer() + idx);
uInt8 c = *(myOSystem->console().tia().currentFrameBuffer() + idx);
uInt8 p = *(myOSystem->console().tia().previousFrameBuffer() + idx);
return (!myUsePhosphor ? myDefPalette[c] : myAvgPalette[c][p]);
}

View File

@ -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: FrameBuffer.hxx,v 1.115 2009-01-10 18:52:55 stephena Exp $
// $Id: FrameBuffer.hxx,v 1.116 2009-01-19 16:52:32 stephena Exp $
//============================================================================
#ifndef FRAMEBUFFER_HXX
@ -83,15 +83,15 @@ enum {
/**
This class encapsulates the MediaSource and is the basis for the video
This class encapsulates all video buffers and is the basis for the video
display in Stella. All graphics ports should derive from this class for
platform-specific video stuff.
All GUI elements (ala ScummVM) are drawn into FBSurfaces, which are in
turn drawn here as well.
The TIA is drawn here, and all GUI elements (ala ScummVM, which are drawn
into FBSurfaces), are in turn drawn here as well.
@author Stephen Anthony
@version $Id: FrameBuffer.hxx,v 1.115 2009-01-10 18:52:55 stephena Exp $
@version $Id: FrameBuffer.hxx,v 1.116 2009-01-19 16:52:32 stephena Exp $
*/
class FrameBuffer
{
@ -118,7 +118,7 @@ class FrameBuffer
/**
Updates the display, which depending on the current mode could mean
drawing the mediasource, any pending menus, etc.
drawing the TIA, any pending menus, etc.
*/
void update();
@ -247,7 +247,7 @@ class FrameBuffer
const StringMap& supportedTIAFilters(const string& type);
/**
Get the TIA pixel associated with the given MediaSrc index.
Get the TIA pixel associated with the given TIA buffer index.
*/
uInt32 tiaPixel(uInt32 idx) const;
@ -383,10 +383,10 @@ class FrameBuffer
virtual FBSurface* createSurface(int w, int h, bool useBase = false) const = 0;
/**
This method should be called anytime the MediaSource needs to be redrawn
This method should be called anytime the TIA needs to be redrawn
to the screen (full indicating that a full redraw is required).
*/
virtual void drawMediaSource(bool full) = 0;
virtual void drawTIA(bool full) = 0;
/**
This method is called after any drawing is done (per-frame).
@ -563,7 +563,7 @@ class FrameBuffer
FrameBuffer type.
@author Stephen Anthony
@version $Id: FrameBuffer.hxx,v 1.115 2009-01-10 18:52:55 stephena Exp $
@version $Id: FrameBuffer.hxx,v 1.116 2009-01-19 16:52:32 stephena Exp $
*/
// Text alignment modes for drawString()
enum TextAlignment {

View File

@ -1,44 +0,0 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2009 by Bradford W. Mott and the Stella team
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: MediaSrc.cxx,v 1.6 2009-01-01 18:13:36 stephena Exp $
//============================================================================
#include <assert.h>
#include "MediaSrc.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MediaSource::MediaSource()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MediaSource::~MediaSource()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MediaSource::MediaSource(const MediaSource&)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MediaSource& MediaSource::operator = (const MediaSource&)
{
assert(false);
return *this;
}

View File

@ -1,139 +0,0 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2009 by Bradford W. Mott and the Stella team
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: MediaSrc.hxx,v 1.20 2009-01-01 18:13:36 stephena Exp $
//============================================================================
#ifndef MEDIASOURCE_HXX
#define MEDIASOURCE_HXX
#include <string>
class MediaSource;
class Sound;
#include "bspf.hxx"
/**
This class provides an interface for accessing graphics and audio data.
@author Bradford W. Mott
@version $Id: MediaSrc.hxx,v 1.20 2009-01-01 18:13:36 stephena Exp $
*/
class MediaSource
{
public:
/**
Create a new media source
*/
MediaSource();
/**
Destructor
*/
virtual ~MediaSource();
public:
/**
This method should be called at an interval corresponding to the
desired frame rate to update the media source. Invoking this method
will update the graphics buffer and generate the corresponding audio
samples.
*/
virtual void update() = 0;
/**
Answers the current frame buffer
@return Pointer to the current frame buffer
*/
virtual uInt8* currentFrameBuffer() const = 0;
/**
Answers the previous frame buffer
@return Pointer to the previous frame buffer
*/
virtual uInt8* previousFrameBuffer() const = 0;
#ifdef DEBUGGER_SUPPORT
/**
This method should be called whenever a new scanline is to be drawn.
Invoking this method will update the graphics buffer and generate
the corresponding audio samples.
*/
virtual void updateScanline() = 0;
/**
This method should be called whenever a new partial scanline is to be
drawn by stepping one CPU instruction. Invoking this method will update the
graphics buffer and generate the corresponding audio samples.
*/
virtual void updateScanlineByStep() = 0;
/**
This method should be called whenever a new partial scanline is to be
drawn by tracing to target address. Invoking this method will update the
graphics buffer and generate the corresponding audio samples.
*/
virtual void updateScanlineByTrace(int target) = 0;
#endif
public:
/**
Answers the height of the frame buffer
@return The frame's height
*/
virtual uInt32 height() const = 0;
/**
Answers the width of the frame buffer
@return The frame's width
*/
virtual uInt32 width() const = 0;
public:
/**
Enables/disables auto-frame calculation. If enabled, the
MediaSource should re-adjust the framerate at regular intervals.
@param mode Whether to enable or disable all auto-frame calculation
*/
virtual void enableAutoFrame(bool mode) = 0;
/**
Answers the total number of scanlines the media source generated
in producing the current frame buffer.
@return The total number of scanlines generated
*/
virtual uInt32 scanlines() const = 0;
/**
Sets the sound device for the TIA.
*/
virtual void setSound(Sound& sound) = 0;
private:
// Copy constructor isn't supported by this class so make it private
MediaSource(const MediaSource&);
// Assignment operator isn't supported by this class so make it private
MediaSource& operator = (const MediaSource&);
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -13,20 +13,19 @@
// 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.50 2009-01-13 01:18:25 stephena Exp $
// $Id: TIA.hxx,v 1.51 2009-01-19 16:52:32 stephena Exp $
//============================================================================
#ifndef TIA_HXX
#define TIA_HXX
class Console;
class System;
class Settings;
#include "bspf.hxx"
#include "Sound.hxx"
#include "Device.hxx"
#include "MediaSrc.hxx"
#include "System.hxx"
/**
This class is a device that emulates the Television Interface Adapator
@ -40,9 +39,9 @@ class Settings;
be displayed on screen.
@author Bradford W. Mott
@version $Id: TIA.hxx,v 1.50 2009-01-13 01:18:25 stephena Exp $
@version $Id: TIA.hxx,v 1.51 2009-01-19 16:52:32 stephena Exp $
*/
class TIA : public Device , public MediaSource
class TIA : public Device
{
public:
friend class TIADebug;
@ -64,19 +63,19 @@ class TIA : public Device , public MediaSource
/**
Reset device to its power-on state
*/
virtual void reset();
void reset();
/**
Reset frame to change XStart/YStart/Width/Height properties
*/
virtual void frameReset();
void frameReset();
/**
Notification method invoked by the system right before the
system resets its cycle counter to zero. It may be necessary
to override this method for devices that remember cycle counts.
*/
virtual void systemCyclesReset();
void systemCyclesReset();
/**
Install TIA in the specified system. Invoked by the system
@ -84,7 +83,7 @@ class TIA : public Device , public MediaSource
@param system The system the device should install itself in
*/
virtual void install(System& system);
void install(System& system);
/**
Install TIA in the specified system and device. Invoked by
@ -95,7 +94,7 @@ class TIA : public Device , public MediaSource
@param system The system the device should install itself in
@param device The device responsible for this address space
*/
virtual void install(System& system, Device& device);
void install(System& system, Device& device);
/**
Save the current state of this device to the given Serializer.
@ -103,7 +102,7 @@ class TIA : public Device , public MediaSource
@param out The Serializer object to use
@return False on any errors, else true
*/
virtual bool save(Serializer& out) const;
bool save(Serializer& out) const;
/**
Load the current state of this device from the given Deserializer.
@ -111,22 +110,21 @@ class TIA : public Device , public MediaSource
@param in The Deserializer object to use
@return False on any errors, else true
*/
virtual bool load(Deserializer& in);
bool load(Deserializer& in);
/**
Get a descriptor for the device name (used in error checking).
@return The name of the object
*/
virtual string name() const { return "TIA"; }
string name() const { return "TIA"; }
public:
/**
Get the byte at the specified address
@return The byte at the specified address
*/
virtual uInt8 peek(uInt16 address);
uInt8 peek(uInt16 address);
/**
Change the byte at the specified address to the given value
@ -134,14 +132,14 @@ class TIA : public Device , public MediaSource
@param address The address where the value should be stored
@param value The value to be stored at the address
*/
virtual void poke(uInt16 address, uInt8 value);
void poke(uInt16 address, uInt8 value);
public:
/**
This method should be called at an interval corresponding to
the desired frame rate to update the media source.
This method should be called at an interval corresponding to the
desired frame rate to update the TIA. Invoking this method will update
the graphics buffer and generate the corresponding audio samples.
*/
virtual void update();
void update();
/**
Answers the current frame buffer
@ -158,18 +156,10 @@ class TIA : public Device , public MediaSource
uInt8* previousFrameBuffer() const { return myPreviousFrameBuffer; }
/**
Answers the height of the frame buffer
@return The frame's height
Answers the width and height of the frame buffer
*/
uInt32 height() const;
/**
Answers the width of the frame buffer
@return The frame's width
*/
uInt32 width() const;
inline uInt32 width() const { return myFrameWidth; }
inline uInt32 height() const { return myFrameHeight; }
/**
Enables/disables auto-frame calculation. If enabled, the TIA
@ -180,26 +170,28 @@ class TIA : public Device , public MediaSource
void enableAutoFrame(bool mode) { myAutoFrameEnabled = mode; }
/**
Answers the total number of scanlines the media source generated
in producing the current frame buffer. For partial frames, this
will be the current scanline.
Answers the current color clock we've gotten to on this scanline.
@return The current color clock
*/
inline uInt32 clocksThisLine() const
{ return ((mySystem->cycles() * 3) - myClockWhenFrameStarted) % 228; }
/**
Answers the total number of scanlines the TIA generated in producing
the current frame buffer. For partial frames, this will be the
current scanline.
@return The total number of scanlines generated
*/
uInt32 scanlines() const;
inline uInt32 scanlines() const
{ return ((mySystem->cycles() * 3) - myClockWhenFrameStarted) / 228; }
/**
Sets the sound device for the TIA.
*/
void setSound(Sound& sound);
/**
Answers the current color clock we've gotten to on this scanline.
@return The current color clock
*/
uInt32 clocksThisLine() const;
enum TIABit {
P0, // Descriptor for Player 0 Bit
P1, // Descriptor for Player 1 Bit
@ -214,64 +206,43 @@ class TIA : public Device , public MediaSource
@return Whether the bit was enabled or disabled
*/
bool enableBit(TIABit b, bool mode) { myBitEnabled[b] = mode; return mode; }
void enableBit(TIABit b, bool mode) { myBitEnabled[b] = mode ? 0xff : 0x00; }
/**
Toggles the specified TIA bit.
@return Whether the bit was enabled or disabled
*/
bool toggleBit(TIABit b) { myBitEnabled[b] = !myBitEnabled[b]; return myBitEnabled[b]; }
bool toggleBit(TIABit b)
{ myBitEnabled[b] = myBitEnabled[b] == 0xff ? 0x00 : 0xff; return myBitEnabled[b]; }
/**
Enables/disables all TIABit bits.
@param mode Whether to enable or disable all bits
*/
void enableBits(bool mode) { for(uInt8 i = 0; i < 6; ++i) myBitEnabled[i] = mode; }
void enableBits(bool mode)
{ for(uInt8 i = 0; i < 6; ++i) myBitEnabled[i] = mode ? 0xff : 0x00; }
#ifdef DEBUGGER_SUPPORT
/**
This method should be called to update the media source with
a new scanline.
This method should be called to update the TIA with a new scanline.
*/
virtual void updateScanline();
void updateScanline();
/**
This method should be called to update the media source with
a new partial scanline by stepping one CPU instruction.
This method should be called to update the TIA with a new partial
scanline by stepping one CPU instruction.
*/
virtual void updateScanlineByStep();
void updateScanlineByStep();
/**
This method should be called to update the media source with
a new partial scanline by tracing to target address.
This method should be called to update the TIA with a new partial
scanline by tracing to target address.
*/
virtual void updateScanlineByTrace(int target);
void updateScanlineByTrace(int target);
#endif
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 position reset when table
void computePlayerPositionResetWhenTable();
// Compute the player reflect table
void computePlayerReflectTable();
// Compute playfield mask table
void computePlayfieldMaskTable();
private:
// Update the current frame buffer up to one scanline
void updateFrameScanline(uInt32 clocksToUpdate, uInt32 hpos);
@ -307,20 +278,6 @@ class TIA : public Device , public MediaSource
// Sound object the TIA is associated with
Sound* mySound;
private:
// Indicates if color loss should be enabled or disabled. Color loss
// occurs on PAL (and maybe SECAM) systems when the previous frame
// contains an odd number of scanlines.
bool myColorLossEnabled;
// Indicates whether we're done with the current frame. poke() clears this
// when VSYNC is strobed or the max scanlines/frame limit is hit.
bool myPartialFrameFlag;
private:
// Number of frames displayed by this TIA
int myFrameCounter;
// Pointer to the current frame buffer
uInt8* myCurrentFrameBuffer;
@ -330,10 +287,7 @@ class TIA : public Device , public MediaSource
// Pointer to the next pixel that will be drawn in the current frame buffer
uInt8* myFramePointer;
// Indicates where the scanline should start being displayed
uInt32 myFrameXStart;
// Indicates the width of the scanline
// Indicates the width of the visible scanline
uInt32 myFrameWidth;
// Indicated what scanline the frame should start being drawn at
@ -348,7 +302,6 @@ class TIA : public Device , public MediaSource
// Indicates offset in color clocks when display should stop
uInt32 myStopDisplayOffset;
private:
// Indicates color clocks when the current frame began
Int32 myClockWhenFrameStarted;
@ -366,6 +319,21 @@ class TIA : public Device , public MediaSource
// displayed portion of the frame.
Int32 myClocksToEndOfScanLine;
// The color clocks elapsed so far for each of the graphical objects,
// as denoted by 'MOTCK' line described in A. Towers TIA Hardware Notes
Int32 myMotionClockP0;
Int32 myMotionClockP1;
Int32 myMotionClockM0;
Int32 myMotionClockM1;
Int32 myMotionClockBL;
// Indicates 'start' signal for each of the graphical objects as
// described in A. Towers TIA Hardware Notes
Int32 myStartP0;
Int32 myStartP1;
Int32 myStartM0;
Int32 myStartM1;
// Indicates the total number of scanlines generated by the last frame
Int32 myScanlineCountForLastFrame;
@ -378,7 +346,6 @@ class TIA : public Device , public MediaSource
// Color clock when VSYNC ending causes a new frame to be started
Int32 myVSYNCFinishClock;
private:
uInt8 myVSYNC; // Holds the VSYNC register value
uInt8 myVBLANK; // Holds the VBLANK register value
@ -389,10 +356,10 @@ class TIA : public Device , public MediaSource
uInt32 myColor[4];
uInt8 myPriorityEncoder[2][256];
uInt32& myCOLUBK; // Background color register (replicated 4 times)
uInt32& myCOLUPF; // Playfield color register (replicated 4 times)
uInt32& myCOLUP0; // Player 0 color register (replicated 4 times)
uInt32& myCOLUP1; // Player 1 color register (replicated 4 times)
uInt32& myCOLUBK; // Background color register (replicated 4 times)
uInt32& myCOLUPF; // Playfield color register (replicated 4 times)
uInt32& myCOLUP0; // Player 0 color register (replicated 4 times)
uInt32& myCOLUP1; // Player 1 color register (replicated 4 times)
uInt8 myCTRLPF; // Playfield control register
@ -426,17 +393,16 @@ class TIA : public Device , public MediaSource
bool myRESMP0; // Indicates if missle 0 is reset to player 0
bool myRESMP1; // Indicates if missle 1 is reset to player 1
uInt16 myCollision; // Collision register
uInt16 myCollision; // Collision register
// Note that these position registers contain the color clock
// on which the object's serial output should begin (0 to 159)
Int16 myPOSP0; // Player 0 position register
Int16 myPOSP1; // Player 1 position register
Int16 myPOSM0; // Missle 0 position register
Int16 myPOSM1; // Missle 1 position register
Int16 myPOSBL; // Ball position register
Int16 myPOSP0; // Player 0 position register
Int16 myPOSP1; // Player 1 position register
Int16 myPOSM0; // Missle 0 position register
Int16 myPOSM1; // Missle 1 position register
Int16 myPOSBL; // Ball position register
private:
// Graphics for Player 0 that should be displayed. This will be
// reflected if the player is being reflected.
uInt8 myCurrentGRP0;
@ -475,23 +441,18 @@ class TIA : public Device , public MediaSource
uInt8 myAUDF0;
uInt8 myAUDF1;
private:
// Indicates when the dump for paddles was last set
Int32 myDumpDisabledCycle;
// Indicates if the dump is current enabled for the paddles
bool myDumpEnabled;
private:
// Color clock when last HMOVE occured
Int32 myLastHMOVEClock;
// Indicates if HMOVE blanks are currently enabled
bool myHMOVEBlankEnabled;
// Indicates if we're allowing HMOVE blanks to be enabled
bool myAllowHMOVEBlanks;
// Indicates if unused TIA pins are floating on a peek
bool myFloatTIAOutputPins;
@ -504,8 +465,19 @@ class TIA : public Device , public MediaSource
// 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];
// Determines whether specified bits (from TIABit) are enabled or disabled
// Each value is and'ed with the appropriate register, so the valid values
// are 0x00 or 0xff;
uInt8 myBitEnabled[6];
// Indicates if color loss should be enabled or disabled. Color loss
// occurs on PAL (and maybe SECAM) systems when the previous frame
// contains an odd number of scanlines.
bool myColorLossEnabled;
// Indicates whether we're done with the current frame. poke() clears this
// when VSYNC is strobed or the max scanlines/frame limit is hit.
bool myPartialFrameFlag;
// Has current frame been "greyed out" (has updateScanline() been run?)
bool myFrameGreyed;
@ -513,119 +485,12 @@ class TIA : public Device , public MediaSource
// Automatic framerate correction based on number of scanlines
bool myAutoFrameEnabled;
// Number of frames displayed by this TIA
int myFrameCounter;
// 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];
// Used to set the collision register to the correct value
static uInt16 ourCollisionTable[64];
// A mask table which can be used when an object is disabled
static uInt8 ourDisabledMaskTable[640];
// Indicates the update delay associated with poking at a TIA address
static const Int16 ourPokeDelayTable[64];
// Missle mask table (entries are true or false)
static uInt8 ourMissleMaskTable[4][8][4][320];
// Used to convert value written in a motion register into
// its internal representation
static const Int32 ourCompleteMotionTable[76][16];
// Indicates if HMOVE blanks should occur for the corresponding cycle
static const bool ourHMOVEBlankEnableCycles[76];
// Player mask table
static uInt8 ourPlayerMaskTable[4][2][8][320];
// Indicates if player is being reset during delay, display or other times
static Int8 ourPlayerPositionResetWhenTable[8][160][160];
// Used to reflect a players graphics
static uInt8 ourPlayerReflectTable[256];
// Playfield mask table for reflected and non-reflected playfields
static uInt32 ourPlayfieldTable[2][160];
private:
// Copy constructor isn't supported by this class so make it private
TIA(const TIA&);

View File

@ -0,0 +1,644 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2009 by Bradford W. Mott and the Stella team
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: TIATables.cxx,v 1.1 2009-01-19 16:52:32 stephena Exp $
//============================================================================
#include <cassert>
#include "bspf.hxx"
#include "TIATables.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIATables::computeAllTables()
{
for(uInt32 i = 0; i < 640; ++i)
DisabledMaskTable[i] = 0;
computeBallMaskTable();
computeCollisionTable();
computeMissleMaskTable();
computePlayerMaskTable();
computePlayerPositionResetWhenTable();
computePlayerReflectTable();
computePlayfieldMaskTable();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIATables::computeBallMaskTable()
{
// First, calculate masks for alignment 0
for(Int32 size = 0; size < 4; ++size)
{
Int32 x;
// Set all of the masks to false to start with
for(x = 0; x < 160; ++x)
{
BallMaskTable[0][size][x] = false;
}
// Set the necessary fields true
for(x = 0; x < 160 + 8; ++x)
{
if((x >= 0) && (x < (1 << size)))
{
BallMaskTable[0][size][x % 160] = true;
}
}
// Copy fields into the wrap-around area of the mask
for(x = 0; x < 160; ++x)
{
BallMaskTable[0][size][x + 160] = BallMaskTable[0][size][x];
}
}
// Now, copy data for alignments of 1, 2 and 3
for(uInt32 align = 1; align < 4; ++align)
{
for(uInt32 size = 0; size < 4; ++size)
{
for(uInt32 x = 0; x < 320; ++x)
{
BallMaskTable[align][size][x] = BallMaskTable[0][size][(x + 320 - align) % 320];
}
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIATables::computeCollisionTable()
{
for(uInt8 i = 0; i < 64; ++i)
{
CollisionTable[i] = 0;
if((i & M0Bit) && (i & P1Bit)) // M0-P1
CollisionTable[i] |= 0x0001;
if((i & M0Bit) && (i & P0Bit)) // M0-P0
CollisionTable[i] |= 0x0002;
if((i & M1Bit) && (i & P0Bit)) // M1-P0
CollisionTable[i] |= 0x0004;
if((i & M1Bit) && (i & P1Bit)) // M1-P1
CollisionTable[i] |= 0x0008;
if((i & P0Bit) && (i & PFBit)) // P0-PF
CollisionTable[i] |= 0x0010;
if((i & P0Bit) && (i & BLBit)) // P0-BL
CollisionTable[i] |= 0x0020;
if((i & P1Bit) && (i & PFBit)) // P1-PF
CollisionTable[i] |= 0x0040;
if((i & P1Bit) && (i & BLBit)) // P1-BL
CollisionTable[i] |= 0x0080;
if((i & M0Bit) && (i & PFBit)) // M0-PF
CollisionTable[i] |= 0x0100;
if((i & M0Bit) && (i & BLBit)) // M0-BL
CollisionTable[i] |= 0x0200;
if((i & M1Bit) && (i & PFBit)) // M1-PF
CollisionTable[i] |= 0x0400;
if((i & M1Bit) && (i & BLBit)) // M1-BL
CollisionTable[i] |= 0x0800;
if((i & BLBit) && (i & PFBit)) // BL-PF
CollisionTable[i] |= 0x1000;
if((i & P0Bit) && (i & P1Bit)) // P0-P1
CollisionTable[i] |= 0x2000;
if((i & M0Bit) && (i & M1Bit)) // M0-M1
CollisionTable[i] |= 0x4000;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIATables::computeMissleMaskTable()
{
// First, calculate masks for alignment 0
Int32 x, size, number;
// Clear the missle table to start with
for(number = 0; number < 8; ++number)
for(size = 0; size < 4; ++size)
for(x = 0; x < 160; ++x)
MissleMaskTable[0][number][size][x] = false;
for(number = 0; number < 8; ++number)
{
for(size = 0; size < 4; ++size)
{
for(x = 0; x < 160 + 72; ++x)
{
// Only one copy of the missle
if((number == 0x00) || (number == 0x05) || (number == 0x07))
{
if((x >= 0) && (x < (1 << size)))
MissleMaskTable[0][number][size][x % 160] = true;
}
// Two copies - close
else if(number == 0x01)
{
if((x >= 0) && (x < (1 << size)))
MissleMaskTable[0][number][size][x % 160] = true;
else if(((x - 16) >= 0) && ((x - 16) < (1 << size)))
MissleMaskTable[0][number][size][x % 160] = true;
}
// Two copies - medium
else if(number == 0x02)
{
if((x >= 0) && (x < (1 << size)))
MissleMaskTable[0][number][size][x % 160] = true;
else if(((x - 32) >= 0) && ((x - 32) < (1 << size)))
MissleMaskTable[0][number][size][x % 160] = true;
}
// Three copies - close
else if(number == 0x03)
{
if((x >= 0) && (x < (1 << size)))
MissleMaskTable[0][number][size][x % 160] = true;
else if(((x - 16) >= 0) && ((x - 16) < (1 << size)))
MissleMaskTable[0][number][size][x % 160] = true;
else if(((x - 32) >= 0) && ((x - 32) < (1 << size)))
MissleMaskTable[0][number][size][x % 160] = true;
}
// Two copies - wide
else if(number == 0x04)
{
if((x >= 0) && (x < (1 << size)))
MissleMaskTable[0][number][size][x % 160] = true;
else if(((x - 64) >= 0) && ((x - 64) < (1 << size)))
MissleMaskTable[0][number][size][x % 160] = true;
}
// Three copies - medium
else if(number == 0x06)
{
if((x >= 0) && (x < (1 << size)))
MissleMaskTable[0][number][size][x % 160] = true;
else if(((x - 32) >= 0) && ((x - 32) < (1 << size)))
MissleMaskTable[0][number][size][x % 160] = true;
else if(((x - 64) >= 0) && ((x - 64) < (1 << size)))
MissleMaskTable[0][number][size][x % 160] = true;
}
}
// Copy data into wrap-around area
for(x = 0; x < 160; ++x)
MissleMaskTable[0][number][size][x + 160] =
MissleMaskTable[0][number][size][x];
}
}
// Now, copy data for alignments of 1, 2 and 3
for(uInt32 align = 1; align < 4; ++align)
{
for(number = 0; number < 8; ++number)
{
for(size = 0; size < 4; ++size)
{
for(x = 0; x < 320; ++x)
{
MissleMaskTable[align][number][size][x] =
MissleMaskTable[0][number][size][(x + 320 - align) % 320];
}
}
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIATables::computePlayerMaskTable()
{
// First, calculate masks for alignment 0
Int32 x, enable, mode;
// Set the player mask table to all zeros
for(enable = 0; enable < 2; ++enable)
for(mode = 0; mode < 8; ++mode)
for(x = 0; x < 160; ++x)
PlayerMaskTable[0][enable][mode][x] = 0x00;
// Now, compute the player mask table
for(enable = 0; enable < 2; ++enable)
{
for(mode = 0; mode < 8; ++mode)
{
for(x = 0; x < 160 + 72; ++x)
{
if(mode == 0x00)
{
if((enable == 0) && (x >= 0) && (x < 8))
PlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> x;
}
else if(mode == 0x01)
{
if((enable == 0) && (x >= 0) && (x < 8))
PlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> x;
else if(((x - 16) >= 0) && ((x - 16) < 8))
PlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> (x - 16);
}
else if(mode == 0x02)
{
if((enable == 0) && (x >= 0) && (x < 8))
PlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> x;
else if(((x - 32) >= 0) && ((x - 32) < 8))
PlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> (x - 32);
}
else if(mode == 0x03)
{
if((enable == 0) && (x >= 0) && (x < 8))
PlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> x;
else if(((x - 16) >= 0) && ((x - 16) < 8))
PlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> (x - 16);
else if(((x - 32) >= 0) && ((x - 32) < 8))
PlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> (x - 32);
}
else if(mode == 0x04)
{
if((enable == 0) && (x >= 0) && (x < 8))
PlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> x;
else if(((x - 64) >= 0) && ((x - 64) < 8))
PlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> (x - 64);
}
else if(mode == 0x05)
{
// For some reason in double size mode the player's output
// is delayed by one pixel thus we use > instead of >=
if((enable == 0) && (x > 0) && (x <= 16))
PlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> ((x - 1)/2);
}
else if(mode == 0x06)
{
if((enable == 0) && (x >= 0) && (x < 8))
PlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> x;
else if(((x - 32) >= 0) && ((x - 32) < 8))
PlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> (x - 32);
else if(((x - 64) >= 0) && ((x - 64) < 8))
PlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> (x - 64);
}
else if(mode == 0x07)
{
// For some reason in quad size mode the player's output
// is delayed by one pixel thus we use > instead of >=
if((enable == 0) && (x > 0) && (x <= 32))
PlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> ((x - 1)/4);
}
}
// Copy data into wrap-around area
for(x = 0; x < 160; ++x)
{
PlayerMaskTable[0][enable][mode][x + 160] =
PlayerMaskTable[0][enable][mode][x];
}
}
}
// Now, copy data for alignments of 1, 2 and 3
for(uInt32 align = 1; align < 4; ++align)
{
for(enable = 0; enable < 2; ++enable)
{
for(mode = 0; mode < 8; ++mode)
{
for(x = 0; x < 320; ++x)
{
PlayerMaskTable[align][enable][mode][x] =
PlayerMaskTable[0][enable][mode][(x + 320 - align) % 320];
}
}
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIATables::computePlayerPositionResetWhenTable()
{
uInt32 mode, oldx, newx;
// Loop through all player modes, all old player positions, and all new
// player positions and determine where the new position is located:
// 1 means the new position is within the display of an old copy of the
// player, -1 means the new position is within the delay portion of an
// old copy of the player, and 0 means it's neither of these two
for(mode = 0; mode < 8; ++mode)
{
for(oldx = 0; oldx < 160; ++oldx)
{
// Set everything to 0 for non-delay/non-display section
for(newx = 0; newx < 160; ++newx)
{
PlayerPositionResetWhenTable[mode][oldx][newx] = 0;
}
// Now, we'll set the entries for non-delay/non-display section
for(newx = 0; newx < 160 + 72 + 5; ++newx)
{
if(mode == 0x00)
{
if((newx >= oldx) && (newx < (oldx + 4)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
if((newx >= oldx + 4) && (newx < (oldx + 4 + 8)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
}
else if(mode == 0x01)
{
if((newx >= oldx) && (newx < (oldx + 4)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
else if((newx >= (oldx + 16)) && (newx < (oldx + 16 + 4)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
if((newx >= oldx + 4) && (newx < (oldx + 4 + 8)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
else if((newx >= oldx + 16 + 4) && (newx < (oldx + 16 + 4 + 8)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
}
else if(mode == 0x02)
{
if((newx >= oldx) && (newx < (oldx + 4)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
else if((newx >= (oldx + 32)) && (newx < (oldx + 32 + 4)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
if((newx >= oldx + 4) && (newx < (oldx + 4 + 8)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
else if((newx >= oldx + 32 + 4) && (newx < (oldx + 32 + 4 + 8)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
}
else if(mode == 0x03)
{
if((newx >= oldx) && (newx < (oldx + 4)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
else if((newx >= (oldx + 16)) && (newx < (oldx + 16 + 4)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
else if((newx >= (oldx + 32)) && (newx < (oldx + 32 + 4)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
if((newx >= oldx + 4) && (newx < (oldx + 4 + 8)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
else if((newx >= oldx + 16 + 4) && (newx < (oldx + 16 + 4 + 8)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
else if((newx >= oldx + 32 + 4) && (newx < (oldx + 32 + 4 + 8)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
}
else if(mode == 0x04)
{
if((newx >= oldx) && (newx < (oldx + 4)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
else if((newx >= (oldx + 64)) && (newx < (oldx + 64 + 4)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
if((newx >= oldx + 4) && (newx < (oldx + 4 + 8)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
else if((newx >= oldx + 64 + 4) && (newx < (oldx + 64 + 4 + 8)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
}
else if(mode == 0x05)
{
if((newx >= oldx) && (newx < (oldx + 4)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
if((newx >= oldx + 4) && (newx < (oldx + 4 + 16)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
}
else if(mode == 0x06)
{
if((newx >= oldx) && (newx < (oldx + 4)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
else if((newx >= (oldx + 32)) && (newx < (oldx + 32 + 4)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
else if((newx >= (oldx + 64)) && (newx < (oldx + 64 + 4)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
if((newx >= oldx + 4) && (newx < (oldx + 4 + 8)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
else if((newx >= oldx + 32 + 4) && (newx < (oldx + 32 + 4 + 8)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
else if((newx >= oldx + 64 + 4) && (newx < (oldx + 64 + 4 + 8)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
}
else if(mode == 0x07)
{
if((newx >= oldx) && (newx < (oldx + 4)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
if((newx >= oldx + 4) && (newx < (oldx + 4 + 32)))
PlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
}
}
// Let's do a sanity check on table entries
uInt32 s1 = 0, s2 = 0;
for(newx = 0; newx < 160; ++newx)
{
if(PlayerPositionResetWhenTable[mode][oldx][newx] == -1)
++s1;
if(PlayerPositionResetWhenTable[mode][oldx][newx] == 1)
++s2;
}
assert((s1 % 4 == 0) && (s2 % 8 == 0));
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIATables::computePlayerReflectTable()
{
for(uInt16 i = 0; i < 256; ++i)
{
uInt8 r = 0;
for(uInt16 t = 1; t <= 128; t *= 2)
{
r = (r << 1) | ((i & t) ? 0x01 : 0x00);
}
PlayerReflectTable[i] = r;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIATables::computePlayfieldMaskTable()
{
Int32 x;
// Compute playfield mask table for non-reflected mode
for(x = 0; x < 160; ++x)
{
if(x < 16)
PlayfieldTable[0][x] = 0x00001 << (x / 4);
else if(x < 48)
PlayfieldTable[0][x] = 0x00800 >> ((x - 16) / 4);
else if(x < 80)
PlayfieldTable[0][x] = 0x01000 << ((x - 48) / 4);
else if(x < 96)
PlayfieldTable[0][x] = 0x00001 << ((x - 80) / 4);
else if(x < 128)
PlayfieldTable[0][x] = 0x00800 >> ((x - 96) / 4);
else if(x < 160)
PlayfieldTable[0][x] = 0x01000 << ((x - 128) / 4);
}
// Compute playfield mask table for reflected mode
for(x = 0; x < 160; ++x)
{
if(x < 16)
PlayfieldTable[1][x] = 0x00001 << (x / 4);
else if(x < 48)
PlayfieldTable[1][x] = 0x00800 >> ((x - 16) / 4);
else if(x < 80)
PlayfieldTable[1][x] = 0x01000 << ((x - 48) / 4);
else if(x < 112)
PlayfieldTable[1][x] = 0x80000 >> ((x - 80) / 4);
else if(x < 144)
PlayfieldTable[1][x] = 0x00010 << ((x - 112) / 4);
else if(x < 160)
PlayfieldTable[1][x] = 0x00008 >> ((x - 144) / 4);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 TIATables::BallMaskTable[4][4][320];
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 TIATables::CollisionTable[64];
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 TIATables::DisabledMaskTable[640];
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const Int16 TIATables::PokeDelayTable[64] = {
0, 1, 0, 0, 8, 8, 0, 0, 0, 0, 0, 1, 1, -1, -1, -1,
0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 TIATables::MissleMaskTable[4][8][4][320];
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const bool TIATables::HMOVEBlankEnableCycles[76] = {
true, true, true, true, true, true, true, true, true, true, // 00
true, true, true, true, true, true, true, true, true, true, // 10
true, false, false, false, false, false, false, false, false, false, // 20
false, false, false, false, false, false, false, false, false, false, // 30
false, false, false, false, false, false, false, false, false, false, // 40
false, false, false, false, false, false, false, false, false, false, // 50
false, false, false, false, false, false, false, false, false, false, // 60
false, false, false, false, false, true // 70
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const Int32 TIATables::CompleteMotionTable[76][16] = {
{ 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 0, -1, -2, -3, -4, -5, -6, -6, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 0, -1, -2, -3, -4, -5, -5, -5, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 0, -1, -2, -3, -4, -5, -5, -5, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 0, -1, -2, -3, -4, -4, -4, -4, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 0, -1, -2, -3, -3, -3, -3, -3, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 0, -1, -2, -2, -2, -2, -2, -2, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 0, -1, -2, -2, -2, -2, -2, -2, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 0, -1, -1, -1, -1, -1, -1, -1, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 0, 0, 0, 0, 0, 0, 0, 0, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 1, 1, 1, 1, 1, 1, 1, 1, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 1, 1, 1, 1, 1, 1, 1, 1, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
{ 2, 2, 2, 2, 2, 2, 2, 2, 8, 7, 6, 5, 4, 3, 2, 2}, // HBLANK
{ 3, 3, 3, 3, 3, 3, 3, 3, 8, 7, 6, 5, 4, 3, 3, 3}, // HBLANK
{ 4, 4, 4, 4, 4, 4, 4, 4, 8, 7, 6, 5, 4, 4, 4, 4}, // HBLANK
{ 4, 4, 4, 4, 4, 4, 4, 4, 8, 7, 6, 5, 4, 4, 4, 4}, // HBLANK
{ 5, 5, 5, 5, 5, 5, 5, 5, 8, 7, 6, 5, 5, 5, 5, 5}, // HBLANK
{ 6, 6, 6, 6, 6, 6, 6, 6, 8, 7, 6, 6, 6, 6, 6, 6}, // HBLANK
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, -1, -2, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, -1, -2, -3, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, -1, -2, -3, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, -1, -2, -3, -4, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, -1, -2, -3, -4, -5, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, -1, -2, -3, -4, -5, -6, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, -1, -2, -3, -4, -5, -6, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, -1, -2, -3, -4, -5, -6, -7, 0, 0, 0, 0, 0, 0, 0, 0},
{-1, -2, -3, -4, -5, -6, -7, -8, 0, 0, 0, 0, 0, 0, 0, 0},
{-2, -3, -4, -5, -6, -7, -8, -9, 0, 0, 0, 0, 0, 0, 0, -1},
{-2, -3, -4, -5, -6, -7, -8, -9, 0, 0, 0, 0, 0, 0, 0, -1},
{-3, -4, -5, -6, -7, -8, -9,-10, 0, 0, 0, 0, 0, 0, -1, -2},
{-4, -5, -6, -7, -8, -9,-10,-11, 0, 0, 0, 0, 0, -1, -2, -3},
{-5, -6, -7, -8, -9,-10,-11,-12, 0, 0, 0, 0, -1, -2, -3, -4},
{-5, -6, -7, -8, -9,-10,-11,-12, 0, 0, 0, 0, -1, -2, -3, -4},
{-6, -7, -8, -9,-10,-11,-12,-13, 0, 0, 0, -1, -2, -3, -4, -5},
{-7, -8, -9,-10,-11,-12,-13,-14, 0, 0, -1, -2, -3, -4, -5, -6},
{-8, -9,-10,-11,-12,-13,-14,-15, 0, -1, -2, -3, -4, -5, -6, -7},
{-8, -9,-10,-11,-12,-13,-14,-15, 0, -1, -2, -3, -4, -5, -6, -7},
{ 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1} // HBLANK
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 TIATables::PlayerMaskTable[4][2][8][320];
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int8 TIATables::PlayerPositionResetWhenTable[8][160][160];
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 TIATables::PlayerReflectTable[256];
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 TIATables::PlayfieldTable[2][160];

View File

@ -0,0 +1,172 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2009 by Bradford W. Mott and the Stella team
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: TIATables.hxx,v 1.1 2009-01-19 16:52:32 stephena Exp $
//============================================================================
#ifndef TIA_TABLES_HXX
#define TIA_TABLES_HXX
#include "bspf.hxx"
enum {
P0Bit = 0x01, // Bit for Player 0
M0Bit = 0x02, // Bit for Missle 0
P1Bit = 0x04, // Bit for Player 1
M1Bit = 0x08, // Bit for Missle 1
BLBit = 0x10, // Bit for Ball
PFBit = 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
};
/**
The TIA class uses some static tables that aren't dependent on the actual
TIA state. For code organization, it's better to place that functionality
here.
@author Stephen Anthony
@version $Id: TIATables.hxx,v 1.1 2009-01-19 16:52:32 stephena Exp $
*/
class TIATables
{
public:
/**
Compute all static tables used by the TIA
*/
static void computeAllTables();
// Ball mask table (entries are true or false)
static uInt8 BallMaskTable[4][4][320];
// Used to set the collision register to the correct value
static uInt16 CollisionTable[64];
// A mask table which can be used when an object is disabled
static uInt8 DisabledMaskTable[640];
// Indicates the update delay associated with poking at a TIA address
static const Int16 PokeDelayTable[64];
// Missle mask table (entries are true or false)
static uInt8 MissleMaskTable[4][8][4][320];
// Used to convert value written in a motion register into
// its internal representation
static const Int32 CompleteMotionTable[76][16];
// Indicates if HMOVE blanks should occur for the corresponding cycle
static const bool HMOVEBlankEnableCycles[76];
// Player mask table
static uInt8 PlayerMaskTable[4][2][8][320];
// Indicates if player is being reset during delay, display or other times
static Int8 PlayerPositionResetWhenTable[8][160][160];
// Used to reflect a players graphics
static uInt8 PlayerReflectTable[256];
// Playfield mask table for reflected and non-reflected playfields
static uInt32 PlayfieldTable[2][160];
private:
// Compute the ball mask table
static void computeBallMaskTable();
// Compute the collision decode table
static void computeCollisionTable();
// Compute the missle mask table
static void computeMissleMaskTable();
// Compute the player mask table
static void computePlayerMaskTable();
// Compute the player position reset when table
static void computePlayerPositionResetWhenTable();
// Compute the player reflect table
static void computePlayerReflectTable();
// Compute playfield mask table
static void computePlayfieldMaskTable();
};
#endif

View File

@ -41,7 +41,6 @@ MODULE_OBJS := \
src/emucore/M6532.o \
src/emucore/MT24LC256.o \
src/emucore/MD5.o \
src/emucore/MediaSrc.o \
src/emucore/OSystem.o \
src/emucore/Paddles.o \
src/emucore/Props.o \
@ -55,6 +54,7 @@ MODULE_OBJS := \
src/emucore/StateManager.o \
src/emucore/TIA.o \
src/emucore/TIASnd.o \
src/emucore/TIATables.o \
src/emucore/TrackBall.o \
src/emucore/unzip.o \
src/emucore/MediaFactory.o

View File

@ -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: CommandDialog.cxx,v 1.24 2009-01-15 18:45:23 stephena Exp $
// $Id: CommandDialog.cxx,v 1.25 2009-01-19 16:52:32 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -192,7 +192,7 @@ void CommandDialog::handleCommand(CommandSender* sender, int cmd,
instance().eventHandler().leaveMenuMode();
instance().eventHandler().handleEvent(event, 1);
instance().console().switches().update();
instance().console().mediaSource().update();
instance().console().tia().update();
instance().eventHandler().handleEvent(event, 0);
instance().frameBuffer().refresh();
}

View File

@ -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: VideoDialog.cxx,v 1.63 2009-01-14 20:31:07 stephena Exp $
// $Id: VideoDialog.cxx,v 1.64 2009-01-19 16:52:32 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -310,7 +310,7 @@ void VideoDialog::saveConfig()
if(&instance().console())
{
// Make sure auto-frame calculation is only enabled when necessary
instance().console().mediaSource().enableAutoFrame(i <= 0);
instance().console().tia().enableAutoFrame(i <= 0);
instance().console().setFramerate(float(i));
}