Yet more work on the RIOT SWCHA/SWACNT write functionality. I'm now

almost 100% sure the current RIOT write handling is working correctly,
as it works with all ROMs I've tested as well as the SpeakJet portion
of the AtariVox.  I2C EEPROM handling still isn't working, but at least
now it's getting the correct values (in the correct order) from the RIOT.
So it should be much easier to finish, now that the RIOT part is taken
care of.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1498 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2008-05-06 16:39:12 +00:00
parent 27441fadbf
commit 44913019b8
7 changed files with 105 additions and 88 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: EquateList.cxx,v 1.31 2008-05-04 17:16:39 stephena Exp $
// $Id: EquateList.cxx,v 1.32 2008-05-06 16:39:10 stephena Exp $
//============================================================================
#include <fstream>
@ -71,9 +71,9 @@ void EquateList::addEquate(const string& label, int address)
else if((address & 0x1000) == 0x1000)
flags = EQF_RW;
else
{ cerr << "label = " << label << ", address = " << hex << address << " discarded\n";
//{ cerr << "label = " << label << ", address = " << hex << address << " discarded\n";
return; // don't know what else to do for now
}
//}
removeEquate(label);

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: AtariVox.cxx,v 1.18 2008-04-29 20:06:14 stephena Exp $
// $Id: AtariVox.cxx,v 1.19 2008-05-06 16:39:10 stephena Exp $
//============================================================================
#ifdef SPEAKJET_EMULATION
@ -102,6 +102,7 @@ void AtariVox::write(DigitalPin pin, bool value)
// Pin 1: SpeakJet DATA
// output serial data to the speakjet
case One:
myDigitalPinState[One] = value;
clockDataIn(value);
break;
@ -114,6 +115,7 @@ void AtariVox::write(DigitalPin pin, bool value)
<< " written to SDA line at cycle "
<< mySystem.cycles()
<< endl;
myDigitalPinState[Three] = value;
myEEPROM->writeSDA(value);
break;
@ -126,6 +128,7 @@ void AtariVox::write(DigitalPin pin, bool value)
<< " written to SCLK line at cycle "
<< mySystem.cycles()
<< endl;
myDigitalPinState[Four] = value;
myEEPROM->writeSCL(value);
break;
@ -137,10 +140,6 @@ void AtariVox::write(DigitalPin pin, bool value)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AtariVox::clockDataIn(bool value)
{
// Data is normally inverted when sending to the SpeakJet;
// we need to reverse that
// value = !value;
uInt32 cycle = mySystem.cycles();
if(DEBUG_ATARIVOX)
cerr << "AtariVox: value "

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: M6532.cxx,v 1.23 2008-04-28 21:31:40 stephena Exp $
// $Id: M6532.cxx,v 1.24 2008-05-06 16:39:11 stephena Exp $
//============================================================================
#include <assert.h>
@ -137,9 +137,11 @@ uInt8 M6532::peek(uInt16 addr)
if(port1.read(Controller::Three)) value |= 0x04;
if(port1.read(Controller::Four)) value |= 0x08;
// Return the input bits set by the controller *and* the
// output bits set by the last write to SWCHA
return (value & ~myDDRA) | (myOutA & myDDRA);
// Each pin is high (1) by default and will only go low (0) if either
// (a) External device drives the pin low
// (b) Corresponding bit in SWACNT = 1 and SWCHA = 0
// Thanks to A. Herbert for this info
return (myOutA | ~myDDRA) & value;
}
case 0x01: // Port A Data Direction Register
@ -235,59 +237,20 @@ void M6532::poke(uInt16 addr, uInt8 value)
case 0: // Port A I/O Register (Joystick)
{
myOutA = value;
uInt8 a = myOutA & myDDRA;
Controller& port0 = myConsole.controller(Controller::Left);
port0.write(Controller::One, a & 0x10);
port0.write(Controller::Two, a & 0x20);
port0.write(Controller::Three, a & 0x40);
port0.write(Controller::Four, a & 0x80);
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);
setOutputState();
break;
}
case 1: // Port A Data Direction Register
{
myDDRA = value;
/*
Undocumented feature used by the AtariVox and SaveKey.
When the DDR is changed, the ORA (output register A) cached
from a previous write to SWCHA is 'applied' to the controller pins.
When a bit in the DDR is set as input, +5V is placed on its output
pin. When it's set as output, either +5V or 0V (depending on the
contents of SWCHA) will be placed on the output pin.
The standard macros for the AtariVox use this fact to send data
to the port. This is represented by the following algorithm:
if(DDR bit is input) set output as 1
else if(DDR bit is output) set output as bit in ORA
*/
uInt8 a = myOutA | ~myDDRA;
Controller& port0 = myConsole.controller(Controller::Left);
port0.write(Controller::One, a & 0x10);
port0.write(Controller::Two, a & 0x20);
port0.write(Controller::Three, a & 0x40);
port0.write(Controller::Four, a & 0x80);
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);
setOutputState();
break;
}
default: // Port B I/O & DDR Registers (Console switches)
break; // hardwired as read-only
}
}
}
}
@ -303,6 +266,34 @@ void M6532::setTimerRegister(uInt8 value, uInt8 interval)
myCyclesWhenTimerSet = mySystem->cycles();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void M6532::setOutputState()
{
/*
When a bit in the DDR is set as input, +5V is placed on its output
pin. When it's set as output, either +5V or 0V (depending on the
contents of SWCHA) will be placed on the output pin.
The standard macros for the AtariVox use this fact to send data
to the port. This is represented by the following algorithm:
if(DDR bit is input) set output as 1
else if(DDR bit is output) set output as bit in ORA
*/
uInt8 a = myOutA | ~myDDRA;
Controller& port0 = myConsole.controller(Controller::Left);
port0.write(Controller::One, a & 0x10);
port0.write(Controller::Two, a & 0x20);
port0.write(Controller::Three, a & 0x40);
port0.write(Controller::Four, a & 0x80);
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);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool M6532::save(Serializer& out) const
{

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: M6532.hxx,v 1.12 2008-04-23 16:51:11 stephena Exp $
// $Id: M6532.hxx,v 1.13 2008-05-06 16:39:11 stephena Exp $
//============================================================================
#ifndef M6532_HXX
@ -32,7 +32,7 @@ class Deserializer;
RIOT
@author Bradford W. Mott
@version $Id: M6532.hxx,v 1.12 2008-04-23 16:51:11 stephena Exp $
@version $Id: M6532.hxx,v 1.13 2008-05-06 16:39:11 stephena Exp $
*/
class M6532 : public Device
{
@ -131,6 +131,7 @@ class M6532 : public Device
{ return myTimer - (mySystem->cycles() - myCyclesWhenTimerSet); }
void setTimerRegister(uInt8 data, uInt8 interval);
void setOutputState();
private:
// Reference to the console

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: MT24LC256.cxx,v 1.7 2008-04-29 20:06:14 stephena Exp $
// $Id: MT24LC256.cxx,v 1.8 2008-05-06 16:39:11 stephena Exp $
//============================================================================
#include <cassert>
@ -48,7 +48,11 @@ char jpee_msg[256];
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MT24LC256::MT24LC256(const string& filename, const System& system)
: mySystem(system),
mySDA(false),
mySCL(false),
myCyclesWhenTimerSet(0),
myCyclesWhenSDASet(0),
myCyclesWhenSCLSet(0),
myDataFile(filename)
{
// First initialize the I2C state
@ -93,25 +97,42 @@ bool MT24LC256::readSDA()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void MT24LC256::writeSDA(bool state)
{
//cerr << "writeSDA: " << state << endl;
mySDA = state;
myCyclesWhenSDASet = mySystem.cycles();
#define jpee_data(x) ( (x) ? \
(!jpee_mdat && jpee_sdat && jpee_mclk && (jpee_data_stop(),1), jpee_mdat = 1) : \
(jpee_mdat && jpee_sdat && jpee_mclk && (jpee_data_start(),1), jpee_mdat = 0))
jpee_data(state);
update();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void MT24LC256::writeSCL(bool state)
{
//cerr << "writeSCL: " << state << endl;
mySCL = state;
myCyclesWhenSCLSet = mySystem.cycles();
update();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void MT24LC256::update()
{
#define jpee_clock(x) ( (x) ? \
(jpee_mclk = 1) : \
(jpee_mclk && (jpee_clock_fall(),1), jpee_mclk = 0))
jpee_clock(state);
#define jpee_data(x) ( (x) ? \
(!jpee_mdat && jpee_sdat && jpee_mclk && (jpee_data_stop(),1), jpee_mdat = 1) : \
(jpee_mdat && jpee_sdat && jpee_mclk && (jpee_data_start(),1), jpee_mdat = 0))
// These pins have to be updated at the same time
// However, the there's no guarantee that the writeSDA() and writeSDL()
// methods will be called at the same time or in the correct order, so
// we only do the write when they have the same 'timestamp'
if(myCyclesWhenSDASet == myCyclesWhenSCLSet)
{
cerr << endl << "--> SCL = " << mySCL << ", SDA = " << mySDA << " @ " << myCyclesWhenSDASet << endl;
jpee_clock(mySCL);
jpee_data(mySDA);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -127,12 +148,14 @@ void MT24LC256::jpee_init()
for(int i = 0; i < 256; i++)
for(int j = 0; j < 128; j++)
myData[i + j*256] = (i+1)*(j+1);
// jpee_timercheck(1);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void MT24LC256::jpee_data_start()
{
//cerr << " ==> jpee_data_start()\n";
cerr << " ==> jpee_data_start()\n";
/* We have a start condition */
if (jpee_state == 1 && (jpee_nb != 1 || jpee_pptr != 3))
{
@ -161,7 +184,7 @@ void MT24LC256::jpee_data_start()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void MT24LC256::jpee_data_stop()
{
//cerr << " ==> jpee_data_stop()\n";
cerr << " ==> jpee_data_stop()\n";
int i;
if (jpee_state == 1 && jpee_nb != 1)
@ -186,7 +209,7 @@ void MT24LC256::jpee_data_stop()
}
for (i=3; i<jpee_pptr; i++)
{
//cerr << " => writing\n";
cerr << " => writing\n";
myData[(jpee_address++) & jpee_sizemask] = jpee_packet[i];
if (!(jpee_address & jpee_pagemask))
break; /* Writes can't cross page boundary! */
@ -202,7 +225,7 @@ void MT24LC256::jpee_data_stop()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void MT24LC256::jpee_clock_fall()
{
//cerr << " ==> jpee_clock_fall()\n";
cerr << " ==> jpee_clock_fall()\n";
switch(jpee_state)
{
case 1:
@ -318,12 +341,19 @@ bool MT24LC256::jpee_timercheck(int mode)
if(mode) // set timer
{
myCyclesWhenTimerSet = mySystem.cycles();
cerr << " --> timer set: " << myCyclesWhenTimerSet << endl;
return true;
}
else // read timer
{
uInt32 elapsed = mySystem.cycles() - myCyclesWhenTimerSet;
//cerr << " --> elapsed: " << elapsed << endl;
if(elapsed < (uInt32)(5000000.0 / 838.0))
cerr << " --> timer still running: " << elapsed << endl;
else
cerr << " --> timer expired: " << elapsed << endl;
return elapsed < (uInt32)(5000000.0 / 838.0);
}
}
@ -331,7 +361,7 @@ bool MT24LC256::jpee_timercheck(int mode)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int MT24LC256::jpee_logproc(char const *st)
{
// cerr << " " << st << endl;
cerr << " " << st << endl;
return 0;
}

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: MT24LC256.hxx,v 1.2 2008-04-13 23:43:14 stephena Exp $
// $Id: MT24LC256.hxx,v 1.3 2008-05-06 16:39:12 stephena Exp $
//============================================================================
#ifndef MT24LC256_HXX
@ -30,7 +30,7 @@ class System;
(aka Supercat) for the bulk of this code.
@author Stephen Anthony & J. Payson
@version $Id: MT24LC256.hxx,v 1.2 2008-04-13 23:43:14 stephena Exp $
@version $Id: MT24LC256.hxx,v 1.3 2008-05-06 16:39:12 stephena Exp $
*/
class MT24LC256
{
@ -65,6 +65,8 @@ class MT24LC256
int jpee_logproc(char const *st);
bool jpee_timercheck(int mode);
void update();
private:
// The system of the parent controller
const System& mySystem;
@ -72,9 +74,15 @@ class MT24LC256
// The EEPROM data
uInt8 myData[32768];
// Cached state of the SDA and SCL pins on the last write
bool mySDA, mySCL;
// Indicates when the timer was set
uInt32 myCyclesWhenTimerSet;
// Indicates when the SDA and SCL pins were set/written
uInt32 myCyclesWhenSDASet, myCyclesWhenSCLSet;
// The file containing the EEPROM data
string myDataFile;

View File

@ -13,15 +13,13 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: SaveKey.cxx,v 1.1 2008-04-29 15:49:34 stephena Exp $
// $Id: SaveKey.cxx,v 1.2 2008-05-06 16:39:12 stephena Exp $
//============================================================================
#include "MT24LC256.hxx"
#include "System.hxx"
#include "SaveKey.hxx"
#define DEBUG_SAVEKEY 0
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SaveKey::SaveKey(Jack jack, const Event& event, const System& system,
const string& eepromfile)
@ -67,24 +65,14 @@ void SaveKey::write(DigitalPin pin, bool value)
// Pin 3: EEPROM SDA
// output data to the 24LC256 EEPROM using the I2C protocol
case Three:
if(DEBUG_SAVEKEY)
cerr << "SaveKey: value "
<< value
<< " written to SDA line at cycle "
<< mySystem.cycles()
<< endl;
myDigitalPinState[Three] = value;
myEEPROM->writeSDA(value);
break;
// Pin 4: EEPROM SCL
// output clock data to the 24LC256 EEPROM using the I2C protocol
case Four:
if(DEBUG_SAVEKEY)
cerr << "SaveKey: value "
<< value
<< " written to SCLK line at cycle "
<< mySystem.cycles()
<< endl;
myDigitalPinState[Four] = value;
myEEPROM->writeSCL(value);
break;