Preliminary WIP for the Microchip Technology Inc. 24LC256, the EEPROM

used in the AtariVox and SaveKey.  It isn't actually connected yet, and is
basically a C++ wrapper around the I2C routines provided by J. Payson
(aka Supercat).


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1469 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2008-04-13 15:05:59 +00:00
parent 9608280880
commit 86a2a1dceb
3 changed files with 415 additions and 0 deletions

View File

@ -0,0 +1,322 @@
//============================================================================
//
// 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-2008 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: MT24LC256.cxx,v 1.1 2008-04-13 15:05:58 stephena Exp $
//============================================================================
#include <cassert>
#include <fstream>
#include "Control.hxx"
#include "System.hxx"
#include "MT24LC256.hxx"
/*
State values for I2C:
0 - Idle
1 - Byte going to chip (shift left until bit 8 is set)
2 - Chip outputting acknowledgement
3 - Byte coming in from chip (shift left until lower 8 bits are clear)
4 - Chip waiting for acknowledgement
*/
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MT24LC256::MT24LC256(const string& filename, const Controller* controller)
: myController(controller),
myDataFile(filename)
{
// First initialize the I2C state
jpee_init();
// Now load the data from an external file (if it exists)
ifstream in;
in.open(myDataFile.c_str(), ios_base::binary);
if(in.is_open())
{
// Get length of file; it must be 32768
in.seekg(0, ios::end);
if((int)in.tellg() == 32768)
{
in.seekg(0, ios::beg);
in.read((char*)myData, 32768);
}
in.close();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MT24LC256::~MT24LC256()
{
// Save EEPROM data to external file
ofstream out;
out.open(myDataFile.c_str(), ios_base::binary);
if(out.is_open())
{
out.write((char*)myData, 32768);
out.close();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool MT24LC256::readSDA()
{
return jpee_mdat && jpee_sdat;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void MT24LC256::writeSDA(bool state)
{
#if 0
if(state)
(!jpee_mdat && jpee_sdat && jpee_mclk && (jpee_data_stop(),1), jpee_mdat = 1)
else
(jpee_mdat && jpee_sdat && jpee_mclk && (jpee_data_start(),1), jpee_mdat = 0))
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void MT24LC256::writeSCL(bool state)
{
#if 0
if(state)
jpee_mclk = 1;
else
(jpee_mclk && (jpee_clock_fall(),1), jpee_mclk = 0))
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void MT24LC256::jpee_init()
{
jpee_sdat = 1;
jpee_address = 0;
jpee_state=0;
jpee_sizemask = 32767;
jpee_pagemask = 63;
jpee_smallmode = 0;
jpee_logmode = -1;
for(int i = 0; i < 256; i++)
for(int j = 0; j < 128; j++)
myData[i + j*256] = (i+1)*(j+1);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void MT24LC256::jpee_data_start()
{
/* We have a start condition */
if (jpee_state == 1 && (jpee_nb != 1 || jpee_pptr != 3))
{
// JPEE_LOG0(LOG_UNCLEAN,"I2C_WARNING ABANDON WRITE");
jpee_ad_known = 0;
}
if (jpee_state == 3)
{
// JPEE_LOG0(LOG_UNCLEAN,"I2C_WARNING ABANDON READ");
}
if (!jpee_timercheck(0))
{
// JPEE_LOG0(LOG_EVENTS,"I2C_START");
jpee_state = 2;
}
else
{
// JPEE_LOG0(LOG_BUSY,"I2C_BUSY");
jpee_state = 0;
}
jpee_pptr = 0;
jpee_nb = 0;
jpee_packet[0] = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void MT24LC256::jpee_data_stop()
{
int i;
if (jpee_state == 1 && jpee_nb != 1)
{
// JPEE_LOG0(LOG_UNCLEAN,"I2C_WARNING ABANDON_WRITE");
jpee_ad_known = 0;
}
if (jpee_state == 3)
{
// JPEE_LOG0(LOG_UNCLEAN,"I2C_WARNING ABANDON_READ");
jpee_ad_known = 0;
}
/* We have a stop condition. */
if (jpee_state == 1 && jpee_nb == 1 && jpee_pptr > 3)
{
jpee_timercheck(1);
// JPEE_LOG2(LOG_EVENTS,"I2C_STOP(Write %d bytes at %04X)",jpee_pptr-3,jpee_address);
if (((jpee_address + jpee_pptr-4) ^ jpee_address) & ~jpee_pagemask)
{
jpee_pptr = 4+jpee_pagemask-(jpee_address & jpee_pagemask);
// JPEE_LOG1(LOG_ODDBALL,"I2C_WARNING PAGECROSSING!(Truncate to %d bytes)",jpee_pptr-3);
}
for (i=3; i<jpee_pptr; i++)
{
myData[(jpee_address++) & jpee_sizemask] = jpee_packet[i];
if (!(jpee_address & jpee_pagemask))
break; /* Writes can't cross page boundary! */
}
jpee_ad_known = 0;
}
else
;// JPEE_LOG0(LOG_EVENTS,"I2C_STOP");
jpee_state = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void MT24LC256::jpee_clock_fall()
{
switch(jpee_state)
{
case 1:
jpee_nb <<= 1;
jpee_nb |= jpee_mdat;
if (jpee_nb & 256)
{
if (!jpee_pptr)
{
jpee_packet[0] = (unsigned char)jpee_nb;
if (jpee_smallmode && ((jpee_nb & 0xF0) == 0xA0))
{
jpee_packet[1] = (jpee_nb >> 1) & 7;
// if (jpee_packet[1] != (jpee_address >> 8) && (jpee_packet[0] & 1))
// JPEE_LOG0(LOG_ODDBALL,"I2C_WARNING ADDRESS MSB CHANGED");
jpee_nb &= 0x1A1;
}
if (jpee_nb == 0x1A0)
{
// JPEE_LOG1(LOG_EVENTS,"I2C_SENT(%02X--start write)",jpee_packet[0]);
jpee_state = 2;
jpee_sdat = 0;
}
else if (jpee_nb == 0x1A1)
{
jpee_state = 4;
// JPEE_LOG2(LOG_EVENTS,"I2C_SENT(%02X--start read @%04X)",
// jpee_packet[0],jpee_address);
// if (!jpee_ad_known)
// JPEE_LOG0(LOG_ODDBALL,"I2C_WARNING ADDRESS IS UNKNOWN");
jpee_sdat = 0;
}
else
{
// JPEE_LOG1(LOG_ODDBALL,"I2C_WARNING ODDBALL FIRST BYTE!(%02X)",jpee_nb & 0xFF);
jpee_state = 0;
}
}
else
{
jpee_state = 2;
jpee_sdat = 0;
}
}
break;
case 2:
if (jpee_nb)
{
if (!jpee_pptr)
{
jpee_packet[0] = (unsigned char)jpee_nb;
if (jpee_smallmode)
jpee_pptr=2;
else
jpee_pptr=1;
}
else if (jpee_pptr < 70)
{
// JPEE_LOG1(LOG_EVENTS,"I2C_SENT(%02X)",jpee_nb & 0xFF);
jpee_packet[jpee_pptr++] = (unsigned char)jpee_nb;
jpee_address = (jpee_packet[1] << 8) | jpee_packet[2];
if (jpee_pptr > 2)
jpee_ad_known = 1;
}
// else
// JPEE_LOG0(LOG_ODDBALL,"I2C_WARNING OUTPUT_OVERFLOW!");
}
jpee_sdat = 1;
jpee_nb = 1;
jpee_state=1;
break;
case 4:
if (jpee_mdat && jpee_sdat)
{
// JPEE_LOG0(LOG_EVENTS,"I2C_READ_NAK");
jpee_state=0;
break;
}
jpee_state=3;
jpee_nb = (myData[jpee_address & jpee_sizemask] << 1) | 1; /* Fall through */
// JPEE_LOG2(LOG_EVENTS,"I2C_READ(%04X=%02X)",jpee_address,jpee_nb/2);
case 3:
jpee_sdat = !!(jpee_nb & 256);
jpee_nb <<= 1;
if (!(jpee_nb & 510))
{
jpee_state = 4;
jpee_sdat = 1;
jpee_address++;
}
break;
default:
/* Do nothing */
break;
}
// JPEE_LOG2(LOG_EDGES,"I2C_CLOCK (dat=%d/%d)",jpee_mdat,jpee_sdat);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int MT24LC256::jpee_timercheck(int mode)
{
// TODO - implement a timer emulating the delay in accessing the EEPROM
// For now, we assume it's always ready
/*
The application should define a function jpee_timercheck() which is used to
evaluate how long the EEPROM is busy. When invoked with an argument of 1,
the system should start a timer (probably about 5 milliseconds); when invoked
with an argument of 0, it should return zero if the timer has expired or
non-zero if it is still running.
*/
return 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MT24LC256::MT24LC256(const MT24LC256& c)
: myController(c.myController),
myDataFile(c.myDataFile)
{
assert(false);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MT24LC256& MT24LC256::operator = (const MT24LC256&)
{
assert(false);
return *this;
}

View File

@ -0,0 +1,92 @@
//============================================================================
//
// 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-2008 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: MT24LC256.hxx,v 1.1 2008-04-13 15:05:58 stephena Exp $
//============================================================================
#ifndef MT24LC256_HXX
#define MT24LC256_HXX
class Controller;
#include "bspf.hxx"
/**
Emulates a Microchip Technology Inc. 24LC256, a 32KB Serial Electrically
Erasable PROM accessed using the I2C protocol. Thanks to J. Payson
(aka Supercat) for the bulk of this code.
@author Stephen Anthony & J. Payson
@version $Id: MT24LC256.hxx,v 1.1 2008-04-13 15:05:58 stephena Exp $
*/
class MT24LC256
{
public:
/**
Create a new 24LC256 with its data stored in the given file
@param filename Data file representing the EEPROM data
@param controller The controller attached to this device
*/
MT24LC256(const string& filename, const Controller* controller);
/**
Destructor
*/
virtual ~MT24LC256();
public:
/** Read boolean data from the SDA line */
bool readSDA();
/** Write boolean data to the SDA and SCL lines */
void writeSDA(bool state);
void writeSCL(bool state);
private:
// I2C access code provided by Supercat
void jpee_init();
void jpee_data_start();
void jpee_data_stop();
void jpee_clock_fall();
// int jpee_logproc(char const *st);
int jpee_timercheck(int mode);
private:
// The controller attached to this device
const Controller* myController;
// The EEPROM data
uInt8 myData[32768];
// The file containing the EEPROM data
string myDataFile;
// Required for I2C functionality
int jpee_mdat, jpee_sdat, jpee_mclk;
int jpee_sizemask, jpee_pagemask, jpee_smallmode, jpee_logmode;
int jpee_pptr, jpee_state, jpee_nb;
unsigned int jpee_address, jpee_ad_known;
uInt8 jpee_packet[70];
private:
// Copy constructor isn't supported by this class so make it private
MT24LC256(const MT24LC256&);
// Assignment operator isn't supported by this class so make it private
MT24LC256& operator = (const MT24LC256&);
};
#endif

View File

@ -39,6 +39,7 @@ MODULE_OBJS := \
src/emucore/Joystick.o \ src/emucore/Joystick.o \
src/emucore/Keyboard.o \ src/emucore/Keyboard.o \
src/emucore/M6532.o \ src/emucore/M6532.o \
src/emucore/MT24LC256.o \
src/emucore/MD5.o \ src/emucore/MD5.o \
src/emucore/MediaSrc.o \ src/emucore/MediaSrc.o \
src/emucore/OSystem.o \ src/emucore/OSystem.o \