mirror of https://github.com/stella-emu/stella.git
Re-arranged the CompuMate controller code so that it can access both
controllers at once. Stella wasn't initially designed to do this, and the CompuMate is unique in this regard. git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2412 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
parent
80c43f175d
commit
47f151b87c
|
@ -17,37 +17,34 @@
|
|||
// $Id$
|
||||
//============================================================================
|
||||
|
||||
#include "Event.hxx"
|
||||
#include "Control.hxx"
|
||||
#include "System.hxx"
|
||||
#include "CompuMate.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
CompuMate::CompuMate(Jack jack, const Event& event, const System& system)
|
||||
: Controller(jack, event, system, Controller::CompuMate),
|
||||
CompuMate::CompuMate(const Event& event, const System& system)
|
||||
: mySystem(system),
|
||||
myLeftController(0),
|
||||
myRightController(0),
|
||||
myCycleAtLastUpdate(0),
|
||||
myIOPort(0xff)
|
||||
{
|
||||
if(myJack == Left)
|
||||
{
|
||||
myAnalogPinValue[Five] = minimumResistance;
|
||||
myAnalogPinValue[Nine] = maximumResistance;
|
||||
}
|
||||
else
|
||||
{
|
||||
myAnalogPinValue[Five] = maximumResistance;
|
||||
myAnalogPinValue[Nine] = minimumResistance;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
CompuMate::~CompuMate()
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CompuMate::controlWrite()
|
||||
{
|
||||
myLeftController = new CMControl(*this, Controller::Left, event, system);
|
||||
myRightController = new CMControl(*this, Controller::Right, event, system);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CompuMate::update()
|
||||
{
|
||||
uInt32 cycle = mySystem.cycles();
|
||||
|
||||
// Only perform update once for both ports in the same cycle
|
||||
if(myCycleAtLastUpdate != cycle)
|
||||
{
|
||||
myCycleAtLastUpdate = cycle;
|
||||
return;
|
||||
}
|
||||
myCycleAtLastUpdate = cycle;
|
||||
|
||||
// TODO - handle SWCHA changes
|
||||
}
|
||||
|
|
|
@ -25,116 +25,113 @@
|
|||
#include "Event.hxx"
|
||||
|
||||
/**
|
||||
Cartridge class used for SpectraVideo CompuMate bankswitched games.
|
||||
Handler for SpectraVideo CompuMate bankswitched games.
|
||||
|
||||
This is more than just a cartridge mapper - it's also a "computer" add-on.
|
||||
There's two 8K EPROMs soldered on top of each other. There's two short
|
||||
wires with DB-9's on them which you plug into the two controller ports.
|
||||
A 42 or so key membrane keyboard with audio in and audio out, and 2K of RAM.
|
||||
The specifics of the CompuMate format can be found in both the Cart side
|
||||
(CartCM) and the Controller side (CMControl). The CompuMate device is
|
||||
unique for the 2600 in that it requires close co-operation between the
|
||||
cartridge and the left and right controllers.
|
||||
|
||||
There are 4 4K banks selectable at $1000 - $1FFF, and 2K RAM at
|
||||
$1800 - $1FFF (R/W 'line' is available at SWCHA D5, so there's no separate
|
||||
read and write ports).
|
||||
This class acts as a 'parent' for both the left and right CMControl's,
|
||||
taking care of their creation and communication between them.
|
||||
|
||||
Bankswitching is done though the controller ports
|
||||
SWCHA: D7 = Audio input from tape player
|
||||
D6 = Audio out to tape player and 4017 CLK
|
||||
1 -> increase key column (0 to 9)
|
||||
D5 = 4017 RST, and RAM direction. (high = write, low = read)
|
||||
1 -> reset key column to 0 (if D4 = 0)
|
||||
0 -> enable RAM writing (if D4 = 1)
|
||||
D4 = RAM enable: 1 = disable RAM, 0 = enable RAM
|
||||
D3 = keyboard row 1 input (0 = key pressed)
|
||||
D2 = keyboard row 1 input (0 = key pressed)
|
||||
D1 = bank select high bit
|
||||
D0 = bank select low bit
|
||||
|
||||
INPT0: D7 = CTRL key input (0 on startup / 1 = key pressed)
|
||||
INPT1: D7 = always HIGH input (pulled high thru 20K resistor)
|
||||
INPT2: D7 = always HIGH input (pulled high thru 20K resistor)
|
||||
INPT3: D7 = SHIFT key input (0 on startup / 1 = key pressed)
|
||||
INPT4: D7 = keyboard row 0 input (0 = key pressed)
|
||||
INPT5: D7 = keyboard row 2 input (0 = key pressed)
|
||||
|
||||
The keyboard's composed of a 4017 1 of 10 counter, driving the 10 columns of
|
||||
the keyboard. It has 4 rows. The 4 row outputs are buffered by inverters.
|
||||
|
||||
Bit 5 of portA controls the reset line on the 4017. Pulling it high will reset
|
||||
scanning to column 0. Pulling it low will allow the counter to be clocked.
|
||||
|
||||
Bit 6 of portA clocks the 4017. Each rising edge advances the column one
|
||||
count.
|
||||
|
||||
There's 10 columns labelled 0-9, and 4 rows, labelled 0-3.
|
||||
|
||||
Column
|
||||
|
||||
0 1 2 3 4 5 6 7 8 9
|
||||
+---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+
|
||||
| 7 | | 6 | | 8 | | 2 | | 3 | | 0 | | 9 | | 5 | | 1 | | 4 | 0
|
||||
+---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+
|
||||
+---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+
|
||||
| U | | Y | | I | | W | | E | | P | | O | | T | | Q | | R | 1
|
||||
+---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ Row
|
||||
+---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+
|
||||
| J | | H | | K | | S | | D | |ent| | L | | G | | A | | F | 2
|
||||
+---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+
|
||||
+---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+
|
||||
| M | | N | | < | | X | | C | |spc| | > | | B | | Z | | V | 3
|
||||
+---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+
|
||||
|
||||
Function and Shift are separate keys that are read by 2 of the paddle inputs.
|
||||
These two buttons pull the specific paddle input low when pressed.
|
||||
|
||||
Because the inputs are inverted, a low indicates a pressed button, and a high
|
||||
is an unpressed one.
|
||||
|
||||
The audio input/output are designed to drive a tape player. The audio output is
|
||||
buffered through an inverter and 2 resistors and a capacitor to reduce the level
|
||||
to feed it into the tape player.
|
||||
|
||||
The audio input is passed through a .1uf capacitor and is pulled to 1/2 supply
|
||||
by two 20K resistors, then it goes through a hex inverting schmitt trigger to
|
||||
square it up. This then runs into bit 7 of portA.
|
||||
|
||||
This code was heavily borrowed from z26, and uses conventions defined
|
||||
there. Specifically, IOPortA is treated as a complete uInt8, whereas
|
||||
the Stella core actually stores this information in boolean arrays
|
||||
addressable by DigitalPin number.
|
||||
|
||||
@author Stephen Anthony & z26 team
|
||||
@author Stephen Anthony
|
||||
@version $Id$
|
||||
*/
|
||||
class CompuMate : public Controller
|
||||
class CompuMate
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Create a new MindLink controller plugged into the specified jack
|
||||
Create a new CompuMate handler for both left and right ports.
|
||||
Note that this class creates CMControl controllers for both ports,
|
||||
but does not take responsibility for their deletion.
|
||||
|
||||
@param event The event object to use for events
|
||||
@param system The system using this controller
|
||||
*/
|
||||
CompuMate(const Event& event, const System& system);
|
||||
|
||||
/**
|
||||
Destructor
|
||||
Controllers are deleted outside this class
|
||||
*/
|
||||
virtual ~CompuMate() { }
|
||||
|
||||
public:
|
||||
/**
|
||||
Called by the controller(s) when all pins have been written
|
||||
*/
|
||||
void update();
|
||||
|
||||
/**
|
||||
Return the left and right CompuMate controllers
|
||||
*/
|
||||
Controller* leftController() { return (Controller*) myLeftController; }
|
||||
Controller* rightController() { return (Controller*) myRightController; }
|
||||
|
||||
private:
|
||||
// The actual CompuMate controller
|
||||
// More information about these scheme can be found in CartCM.hxx
|
||||
class CMControl : public Controller
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Create a new CMControl controller plugged into the specified jack
|
||||
|
||||
@param handler Class which coordinates between left & right controllers
|
||||
@param jack The jack the controller is plugged into
|
||||
@param event The event object to use for events
|
||||
@param system The system using this controller
|
||||
*/
|
||||
CompuMate(Jack jack, const Event& event, const System& system);
|
||||
CMControl(class CompuMate& handler, Controller::Jack jack, const Event& event,
|
||||
const System& system)
|
||||
: Controller(jack, event, system, Controller::CompuMate),
|
||||
myHandler(handler)
|
||||
{
|
||||
if(myJack == Left)
|
||||
{
|
||||
myAnalogPinValue[Five] = minimumResistance;
|
||||
myAnalogPinValue[Nine] = maximumResistance;
|
||||
}
|
||||
else
|
||||
{
|
||||
myAnalogPinValue[Five] = maximumResistance;
|
||||
myAnalogPinValue[Nine] = minimumResistance;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Destructor
|
||||
*/
|
||||
virtual ~CompuMate();
|
||||
virtual ~CMControl() { }
|
||||
|
||||
public:
|
||||
/**
|
||||
Called after *all* digital pins have been written on Port A.
|
||||
*/
|
||||
void controlWrite();
|
||||
void controlWrite() { myHandler.update(); }
|
||||
|
||||
/**
|
||||
Update the entire digital and analog pin state according to the
|
||||
events currently set.
|
||||
*/
|
||||
void update();
|
||||
void update() { }
|
||||
|
||||
private:
|
||||
class CompuMate& myHandler;
|
||||
};
|
||||
|
||||
private:
|
||||
// System object
|
||||
const System& mySystem;
|
||||
|
||||
// Left and right controllers
|
||||
CMControl *myLeftController, *myRightController;
|
||||
|
||||
// System cycle at which the update() method is called
|
||||
// Multiple calls at the same cycle should be ignored
|
||||
uInt32 myCycleAtLastUpdate;
|
||||
|
||||
// Internal state of the port pins
|
||||
uInt8 myIOPort;
|
||||
};
|
||||
|
|
|
@ -74,6 +74,7 @@ Console::Console(OSystem* osystem, Cartridge* cart, const Properties& props)
|
|||
mySwitches(0),
|
||||
mySystem(0),
|
||||
myCart(cart),
|
||||
myCMHandler(0),
|
||||
myDisplayFormat("NTSC"),
|
||||
myFramerate(60.0),
|
||||
myUserPaletteDefined(false)
|
||||
|
@ -221,6 +222,7 @@ Console::~Console()
|
|||
{
|
||||
delete mySystem;
|
||||
delete mySwitches;
|
||||
delete myCMHandler;
|
||||
delete myControllers[0];
|
||||
delete myControllers[1];
|
||||
}
|
||||
|
@ -610,6 +612,17 @@ void Console::setControllers(const string& rommd5)
|
|||
const string& left = myProperties.get(Controller_Left);
|
||||
const string& right = myProperties.get(Controller_Right);
|
||||
|
||||
// Check for CompuMate controllers; they are special in that a handler
|
||||
// creates them for us, and also that they must be used in both ports
|
||||
if(left == "COMPUMATE" || right == "COMPUMATE")
|
||||
{
|
||||
delete myCMHandler;
|
||||
myCMHandler = new CompuMate(myEvent, *mySystem);
|
||||
myControllers[0] = myCMHandler->leftController();
|
||||
myControllers[1] = myCMHandler->rightController();
|
||||
return;
|
||||
}
|
||||
|
||||
// Swap the ports if necessary
|
||||
int leftPort, rightPort;
|
||||
if(myProperties.get(Console_SwapPorts) == "NO")
|
||||
|
@ -669,10 +682,6 @@ void Console::setControllers(const string& rommd5)
|
|||
{
|
||||
myControllers[leftPort] = new Genesis(Controller::Left, myEvent, *mySystem);
|
||||
}
|
||||
else if(left == "COMPUMATE")
|
||||
{
|
||||
myControllers[leftPort] = new CompuMate(Controller::Left, myEvent, *mySystem);
|
||||
}
|
||||
else if(left == "MINDLINK")
|
||||
{
|
||||
myControllers[leftPort] = new MindLink(Controller::Left, myEvent, *mySystem);
|
||||
|
@ -740,10 +749,6 @@ void Console::setControllers(const string& rommd5)
|
|||
{
|
||||
myControllers[rightPort] = new Genesis(Controller::Right, myEvent, *mySystem);
|
||||
}
|
||||
else if(right == "COMPUMATE")
|
||||
{
|
||||
myControllers[rightPort] = new CompuMate(Controller::Right, myEvent, *mySystem);
|
||||
}
|
||||
else if(right == "KIDVID")
|
||||
{
|
||||
myControllers[rightPort] = new KidVid(Controller::Right, myEvent, *mySystem, rommd5);
|
||||
|
|
|
@ -27,6 +27,7 @@ class System;
|
|||
class TIA;
|
||||
class M6532;
|
||||
class Cartridge;
|
||||
class CompuMate;
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "Control.hxx"
|
||||
|
@ -339,6 +340,9 @@ class Console : public Serializable
|
|||
// A RIOT of my own! (...with apologies to The Clash...)
|
||||
M6532 *myRiot;
|
||||
|
||||
// Pointer to CompuMate handler (only used in CompuMate ROMs)
|
||||
CompuMate* myCMHandler;
|
||||
|
||||
// The currently defined display format (NTSC/PAL/SECAM)
|
||||
string myDisplayFormat;
|
||||
|
||||
|
|
|
@ -67,6 +67,7 @@ class Controller : public Serializable
|
|||
Riot debug class needs special access to the underlying controller state
|
||||
*/
|
||||
friend class RiotDebug;
|
||||
friend class CompuMate;
|
||||
|
||||
public:
|
||||
/**
|
||||
|
|
|
@ -2366,7 +2366,7 @@ static const char* DefProps[DEF_PROPS_SIZE][21] = {
|
|||
{ "b9336ed6d94a5cc81a16483b0a946a73", "Atari, Jerome Domurat, Michael Sierchio", "CX2667, CX2667P", "RealSports Soccer (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" },
|
||||
{ "b958d5fd9574c5cf9ece4b9421c28ecd", "Piero Cavina", "", "Multi-Sprite Game V1.0 (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
|
||||
{ "b95a6274ca0e0c773bfdc06b4c3daa42", "Paul Slocum", "", "3-D Corridor (29-03-2003) (Paul Slocum)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
|
||||
{ "b98cc2c6f7a0f05176f74f0f62c45488", "Spectravideo", "SV-010", "CompuMate (1983) (Spectravideo)", "", "", "", "CM", "", "", "", "", "COMPUMATE", "COMPUMATE", "", "", "", "", "", "YES", "" },
|
||||
{ "b98cc2c6f7a0f05176f74f0f62c45488", "Spectravideo", "SV-010", "CompuMate (1983) (Spectravideo)", "", "", "", "CM", "", "", "", "", "COMPUMATE", "COMPUMATE", "", "", "NTSC", "", "", "YES", "" },
|
||||
{ "b9b4612358a0b2c1b4d66bb146767306", "Commavid, Ben Burch", "CM-010", "Rush Hour (1983) (Commavid) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "20", "230", "", "" },
|
||||
{ "b9d1e3be30b131324482345959aed5e5", "Activision, Rex Bradford", "", "Kabobber (07-25-1983) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
|
||||
{ "b9f6fa399b8cd386c235983ec45e4355", "Parker Brothers, John Emerson", "931511", "Action Force (1983) (Parker Bros) (PAL)", "AKA G.I. Joe - Cobra Strike", "", "", "", "", "", "", "", "PADDLES", "", "", "01", "", "", "", "", "" },
|
||||
|
@ -2979,7 +2979,7 @@ static const char* DefProps[DEF_PROPS_SIZE][21] = {
|
|||
{ "e7864caaf9ec49ed67b1904ce8602690", "", "", "Donkey Kong 2K3 Pic (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
|
||||
{ "e7a758bb0b43d0f7004e92b9abf4bc83", "", "", "Troll's Adventure (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
|
||||
{ "e7dd8c2e6c100044002c1086d02b366e", "Activision, Steve Cartwright - Ariola", "EAX-013, PAX-013, 711 013-720", "Barnstorming (1982) (Activision) (PAL)", "AKA Die tollkeuhnen Flieger", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
|
||||
{ "e7f005ddb6902c648de098511f6ae2e5", "Spectravideo - Universum", "SV-010", "CompuMate (1983) (Spectravideo) (PAL)", "", "", "", "CM", "", "", "", "", "COMPUMATE", "COMPUMATE", "", "", "", "", "", "YES", "" },
|
||||
{ "e7f005ddb6902c648de098511f6ae2e5", "Spectravideo - Universum", "SV-010", "CompuMate (1983) (Spectravideo) (PAL)", "", "", "", "CM", "", "", "", "", "COMPUMATE", "COMPUMATE", "", "", "PAL", "", "", "YES", "" },
|
||||
{ "e800e4aec7c6c54c9cf3db0d1d030058", "", "", "Qb (2.06) (Retroactive) (Stella)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" },
|
||||
{ "e80a4026d29777c3c7993fbfaee8920f", "", "", "Frisco (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
|
||||
{ "e823b13751e4388f1f2a375d3560a8d7", "Arcadia Corporation, Stephen Harland Landrum", "AR-4105", "Official Frogger (Preview) (1983) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "32", "", "", "" },
|
||||
|
|
|
@ -279,14 +279,18 @@ void M6532::setPinState(bool swcha)
|
|||
port0.write(Controller::Two, a & 0x20);
|
||||
port0.write(Controller::Three, a & 0x40);
|
||||
port0.write(Controller::Four, a & 0x80);
|
||||
if(swcha) port0.controlWrite();
|
||||
|
||||
Controller& port1 = myConsole.controller(Controller::Right);
|
||||
port1.write(Controller::One, a & 0x01);
|
||||
port1.write(Controller::Two, a & 0x02);
|
||||
port1.write(Controller::Three, a & 0x04);
|
||||
port1.write(Controller::Four, a & 0x08);
|
||||
if(swcha) port1.controlWrite();
|
||||
|
||||
if(swcha)
|
||||
{
|
||||
port0.controlWrite();
|
||||
port1.controlWrite();
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -2641,6 +2641,7 @@
|
|||
"Cartridge.Type" "CM"
|
||||
"Controller.Left" "COMPUMATE"
|
||||
"Controller.Right" "COMPUMATE"
|
||||
"Display.Format" "NTSC"
|
||||
"Display.Phosphor" "YES"
|
||||
""
|
||||
|
||||
|
@ -5268,6 +5269,7 @@
|
|||
"Cartridge.Type" "CM"
|
||||
"Controller.Left" "COMPUMATE"
|
||||
"Controller.Right" "COMPUMATE"
|
||||
"Display.Format" "PAL"
|
||||
"Display.Phosphor" "YES"
|
||||
""
|
||||
|
||||
|
|
Loading…
Reference in New Issue