Merge pull request #2045 from greyrogue/master

Add Datel AGP save commands for SRAM/FRAM.  Improve EEPROM.
This commit is contained in:
skidau 2015-02-15 12:57:58 +11:00
commit d601657c99
2 changed files with 133 additions and 35 deletions

View File

@ -90,6 +90,7 @@ void CEXIAgp::LoadFileToROM(const std::string& filename)
void CEXIAgp::LoadFileToEEPROM(const std::string& filename) void CEXIAgp::LoadFileToEEPROM(const std::string& filename)
{ {
// Technically one of EEPROM, Flash, SRAM, FRAM
File::IOFile pStream(filename, "rb"); File::IOFile pStream(filename, "rb");
if (pStream) if (pStream)
{ {
@ -98,57 +99,92 @@ void CEXIAgp::LoadFileToEEPROM(const std::string& filename)
m_eeprom_mask = (m_eeprom_size - 1); m_eeprom_mask = (m_eeprom_size - 1);
m_eeprom.resize(m_eeprom_size); m_eeprom.resize(m_eeprom_size);
pStream.ReadBytes(m_eeprom.data(), filesize); pStream.ReadBytes(m_eeprom.data(), filesize);
if ((m_eeprom_size == 512) || (m_eeprom_size == 8192))
{
// Handle endian read - could be done with byte access in 0xAE commands instead
for (u32 index = 0; index < (m_eeprom_size / 8); index++)
{
u64 NewVal = 0;
for (u32 indexb = 0; indexb < 8; indexb++)
NewVal = (NewVal << 0x8) | m_eeprom[index * 8 + indexb];
((u64*)(m_eeprom.data()))[index] = NewVal;
} }
m_eeprom_add_end = (m_eeprom_size == 512 ? (2 + 6) : (2 + 14));
m_eeprom_add_mask = (m_eeprom_size == 512 ? 0x3F : 0x3FF);
m_eeprom_read_mask = (m_eeprom_size == 512 ? 0x80 : 0x8000);
m_eeprom_status_mask = (m_rom_size == 0x2000000 ? 0x1FFFF00 : 0x1000000);
}
else
m_eeprom_status_mask = 0;
}
else
{
m_eeprom_size = 0;
m_eeprom.clear();
}
} }
void CEXIAgp::SaveFileFromEEPROM(const std::string& filename) void CEXIAgp::SaveFileFromEEPROM(const std::string& filename)
{ {
File::IOFile pStream(filename, "wb"); File::IOFile pStream(filename, "wb");
if (pStream) if (pStream)
{
if ((m_eeprom_size == 512) || (m_eeprom_size == 8192))
{
// Handle endian write - could be done with byte access in 0xAE commands instead
std::vector<u8> temp_eeprom(m_eeprom_size);
for (u32 index = 0; index < (m_eeprom_size / 8); index++)
{
u64 NewVal = ((u64*)(m_eeprom.data()))[index];
for (u32 indexb = 0; indexb < 8; indexb++)
temp_eeprom[index * 8 + (7-indexb)] = (NewVal >> (indexb * 8)) & 0xFF;
}
pStream.WriteBytes(temp_eeprom.data(), m_eeprom_size);
}
else
{ {
pStream.WriteBytes(m_eeprom.data(), m_eeprom_size); pStream.WriteBytes(m_eeprom.data(), m_eeprom_size);
} }
} }
}
u32 CEXIAgp::ImmRead(u32 _uSize) u32 CEXIAgp::ImmRead(u32 _uSize)
{ {
// We don't really care about _uSize
(void)_uSize;
u32 uData = 0; u32 uData = 0;
u8 RomVal1, RomVal2, RomVal3, RomVal4; u8 RomVal1, RomVal2, RomVal3, RomVal4;
switch (m_current_cmd) switch (m_current_cmd)
{ {
case 0xAE000000: case 0xAE000000: // Clock handshake?
uData = 0x5AAA5517; // 17 is precalculated hash uData = 0x5AAA5517; // 17 is precalculated hash
m_current_cmd = 0; m_current_cmd = 0;
break; break;
case 0xAE010000: case 0xAE010000: // Init?
uData = (m_return_pos == 0) ? 0x01020304 : 0xF0020304; // F0 is precalculated hash, 020304 is left over uData = (m_return_pos == 0) ? 0x01020304 : 0xF0020304; // F0 is precalculated hash, 020304 is left over
if (m_return_pos == 1) if (m_return_pos == 1)
m_current_cmd = 0; m_current_cmd = 0;
else else
m_return_pos = 1; m_return_pos = 1;
break; break;
case 0xAE020000: case 0xAE020000: // Read 2 bytes with 24 bit address
if (m_rw_offset == 0x8000000) if (m_eeprom_write_status && ((m_rw_offset & m_eeprom_status_mask) == m_eeprom_status_mask) && (m_eeprom_status_mask != 0))
{ {
RomVal1 = 0x0; RomVal1 = 0x1;
RomVal2 = 0x1; RomVal2 = 0x0;
} }
else else
{ {
RomVal1 = m_rom[m_rw_offset++]; RomVal1 = m_rom[(m_rw_offset++) & m_rom_mask];
RomVal2 = m_rom[m_rw_offset++]; RomVal2 = m_rom[(m_rw_offset++) & m_rom_mask];
} }
CRC8(&RomVal2, 1); CRC8(&RomVal2, 1);
CRC8(&RomVal1, 1); CRC8(&RomVal1, 1);
uData = (RomVal2 << 24) | (RomVal1 << 16) | (m_hash << 8); uData = (RomVal2 << 24) | (RomVal1 << 16) | (m_hash << 8);
m_current_cmd = 0; m_current_cmd = 0;
break; break;
case 0xAE030000: case 0xAE030000: // read the next 4 bytes out of 0x10000 group
if (_uSize == 1) if (_uSize == 1)
{ {
uData = 0xFF000000; uData = 0xFF000000;
@ -156,10 +192,10 @@ u32 CEXIAgp::ImmRead(u32 _uSize)
} }
else else
{ {
RomVal1 = m_rom[m_rw_offset++]; RomVal1 = m_rom[(m_rw_offset++) & m_rom_mask];
RomVal2 = m_rom[m_rw_offset++]; RomVal2 = m_rom[(m_rw_offset++) & m_rom_mask];
RomVal3 = m_rom[m_rw_offset++]; RomVal3 = m_rom[(m_rw_offset++) & m_rom_mask];
RomVal4 = m_rom[m_rw_offset++]; RomVal4 = m_rom[(m_rw_offset++) & m_rom_mask];
CRC8(&RomVal2, 1); CRC8(&RomVal2, 1);
CRC8(&RomVal1, 1); CRC8(&RomVal1, 1);
CRC8(&RomVal4, 1); CRC8(&RomVal4, 1);
@ -167,8 +203,25 @@ u32 CEXIAgp::ImmRead(u32 _uSize)
uData = (RomVal2 << 24) | (RomVal1 << 16) | (RomVal4 << 8) | (RomVal3); uData = (RomVal2 << 24) | (RomVal1 << 16) | (RomVal4 << 8) | (RomVal3);
} }
break; break;
case 0xAE0B0000: case 0xAE040000: // read 1 byte from 16 bit address
RomVal1 = m_eeprom_pos < 4 ? 0xA : (((u64*)m_eeprom.data())[(m_eeprom_cmd >> 1) & 0x3F] >> (m_eeprom_pos - 4)) & 0x1; // ToDo: Flash special handling
if (m_eeprom_size == 0)
RomVal1 = 0xFF;
else
RomVal1 = (m_eeprom.data())[m_eeprom_pos];
CRC8(&RomVal1, 1);
uData = (RomVal1 << 24) | (m_hash << 16);
m_current_cmd = 0;
break;
case 0xAE0B0000: // read 1 bit from DMA with 6 or 14 bit address
// Change to byte access instead of endian file access?
RomVal1 = EE_READ_FALSE;
if ((m_eeprom_size != 0)
&& (m_eeprom_pos >= EE_IGNORE_BITS)
&& ((((u64*)m_eeprom.data())[(m_eeprom_cmd >> 1) & m_eeprom_add_mask]) >> ((EE_DATA_BITS - 1) - (m_eeprom_pos - EE_IGNORE_BITS))) & 0x1)
{
RomVal1 = EE_READ_TRUE;
}
RomVal2 = 0; RomVal2 = 0;
CRC8(&RomVal2, 1); CRC8(&RomVal2, 1);
CRC8(&RomVal1, 1); CRC8(&RomVal1, 1);
@ -176,7 +229,8 @@ u32 CEXIAgp::ImmRead(u32 _uSize)
m_eeprom_pos++; m_eeprom_pos++;
m_current_cmd = 0; m_current_cmd = 0;
break; break;
case 0xAE0C0000: case 0xAE070000: // complete write 1 byte from 16 bit address
case 0xAE0C0000: // complete write 1 bit from dma with 6 or 14 bit address
uData = m_hash << 24; uData = m_hash << 24;
m_current_cmd = 0; m_current_cmd = 0;
break; break;
@ -191,6 +245,7 @@ u32 CEXIAgp::ImmRead(u32 _uSize)
void CEXIAgp::ImmWrite(u32 _uData, u32 _uSize) void CEXIAgp::ImmWrite(u32 _uData, u32 _uSize)
{ {
// 0x00 = Execute current command?
if ((_uSize == 1) && ((_uData & 0xFF000000) == 0)) if ((_uSize == 1) && ((_uData & 0xFF000000) == 0))
return; return;
@ -199,9 +254,10 @@ void CEXIAgp::ImmWrite(u32 _uData, u32 _uSize)
INFO_LOG(EXPANSIONINTERFACE, "AGP command %x", _uData); INFO_LOG(EXPANSIONINTERFACE, "AGP command %x", _uData);
switch (m_current_cmd) switch (m_current_cmd)
{ {
case 0xAE020000: case 0xAE020000: // set up 24 bit address for read 2 bytes
case 0xAE030000: case 0xAE030000: // set up 24 bit address for read (0x10000 byte group)
m_rw_offset = ((_uData & 0xFFFFFF00) >> 7) & m_rom_mask; // 25 bit address shifted one bit right = 24 bits
m_rw_offset = ((_uData & 0xFFFFFF00) >> (8 - 1));
m_return_pos = 0; m_return_pos = 0;
HashCmd = (_uData & 0xFF000000) >> 24; HashCmd = (_uData & 0xFF000000) >> 24;
CRC8(&HashCmd, 1); CRC8(&HashCmd, 1);
@ -210,20 +266,45 @@ void CEXIAgp::ImmWrite(u32 _uData, u32 _uSize)
HashCmd = (_uData & 0x0000FF00) >> 8; HashCmd = (_uData & 0x0000FF00) >> 8;
CRC8(&HashCmd, 1); CRC8(&HashCmd, 1);
break; break;
case 0xAE0C0000: case 0xAE040000: // set up 16 bit address for read 1 byte
if ((m_eeprom_pos < 0x8) || (m_eeprom_pos == ((m_eeprom_cmd & EE_READ) ? 0x8 : 0x48))) // ToDo: Flash special handling
m_eeprom_pos = ((_uData & 0xFFFF0000) >> 0x10) & m_eeprom_mask;
HashCmd = (_uData & 0xFF000000) >> 24;
CRC8(&HashCmd, 1);
HashCmd = (_uData & 0x00FF0000) >> 16;
CRC8(&HashCmd, 1);
break;
case 0xAE070000: // write 1 byte from 16 bit address
// ToDo: Flash special handling
m_eeprom_pos = ((_uData & 0xFFFF0000) >> 0x10) & m_eeprom_mask;
if (m_eeprom_size != 0)
((m_eeprom.data()))[(m_eeprom_pos)] = (_uData & 0x0000FF00) >> 0x8;
HashCmd = (_uData & 0xFF000000) >> 24;
CRC8(&HashCmd, 1);
HashCmd = (_uData & 0x00FF0000) >> 16;
CRC8(&HashCmd, 1);
HashCmd = (_uData & 0x0000FF00) >> 8;
CRC8(&HashCmd, 1);
break;
case 0xAE0C0000: // write 1 bit from dma with 6 or 14 bit address
if ((m_eeprom_pos < m_eeprom_add_end) || (m_eeprom_pos == ((m_eeprom_cmd & m_eeprom_read_mask) ? m_eeprom_add_end : m_eeprom_add_end + EE_DATA_BITS)))
{ {
Mask = (u64)(1 << (0x8-(m_eeprom_pos > 0x8 ? 0x8 : m_eeprom_pos))); Mask = (1ULL << (m_eeprom_add_end - std::min(m_eeprom_pos, m_eeprom_add_end)));
if ((_uData >> 16) & 0x1) if ((_uData >> 16) & 0x1)
m_eeprom_cmd |= Mask; m_eeprom_cmd |= Mask;
else else
m_eeprom_cmd &= ~Mask; m_eeprom_cmd &= ~Mask;
if (m_eeprom_pos == 0x48) if (m_eeprom_pos == m_eeprom_add_end + EE_DATA_BITS)
((u64*)(m_eeprom.data()))[(m_eeprom_cmd >> 1) & 0x3F] = m_eeprom_data; {
// Change to byte access instead of endian file access?
if (m_eeprom_size != 0)
((u64*)(m_eeprom.data()))[(m_eeprom_cmd >> 1) & m_eeprom_add_mask] = m_eeprom_data;
m_eeprom_write_status = true;
}
} }
else else
{ {
Mask = (u64)(1 << (0x47 - m_eeprom_pos)); Mask = (1ULL << (m_eeprom_add_end + EE_DATA_BITS - 1 - m_eeprom_pos));
if ((_uData >> 16) & 0x1) if ((_uData >> 16) & 0x1)
m_eeprom_data |= Mask; m_eeprom_data |= Mask;
else else
@ -237,13 +318,17 @@ void CEXIAgp::ImmWrite(u32 _uData, u32 _uSize)
CRC8(&HashCmd, 1); CRC8(&HashCmd, 1);
break; break;
case 0xAE0B0000: case 0xAE0B0000:
m_eeprom_write_status = false;
break; break;
case 0xAE000000: case 0xAE000000:
case 0xAE010000: case 0xAE010000:
case 0xAE090000: case 0xAE090000: // start DMA
case 0xAE0A0000: m_eeprom_write_status = false; //ToDo: Verify with hardware which commands disable EEPROM CS
default: // Fall-through intentional
case 0xAE0A0000: // end DMA
m_eeprom_pos = 0; m_eeprom_pos = 0;
// Fall-through intentional
default:
m_current_cmd = _uData; m_current_cmd = _uData;
m_return_pos = 0; m_return_pos = 0;
m_hash = 0xFF; m_hash = 0xFF;
@ -264,6 +349,11 @@ void CEXIAgp::DoState(PointerWrap &p)
p.Do(m_eeprom_mask); p.Do(m_eeprom_mask);
p.Do(m_eeprom_pos); p.Do(m_eeprom_pos);
p.Do(m_eeprom_size); p.Do(m_eeprom_size);
p.Do(m_eeprom_add_end);
p.Do(m_eeprom_add_mask);
p.Do(m_eeprom_read_mask);
p.Do(m_eeprom_status_mask);
p.Do(m_eeprom_write_status);
p.Do(m_hash); p.Do(m_hash);
p.Do(m_position); p.Do(m_position);
p.Do(m_return_pos); p.Do(m_return_pos);

View File

@ -23,7 +23,10 @@ public:
private: private:
enum enum
{ {
EE_READ = 0x80 EE_IGNORE_BITS = 0x4,
EE_DATA_BITS = 0x40,
EE_READ_FALSE = 0xA,
EE_READ_TRUE = 0xB,
}; };
int m_slot; int m_slot;
@ -41,8 +44,13 @@ private:
u32 m_address = 0; u32 m_address = 0;
u32 m_rw_offset = 0; u32 m_rw_offset = 0;
u64 m_eeprom_data = 0; u64 m_eeprom_data = 0;
u8 m_eeprom_pos = 0; u16 m_eeprom_pos = 0;
u16 m_eeprom_cmd = 0; u32 m_eeprom_cmd = 0;
u16 m_eeprom_add_end = 0;
u16 m_eeprom_add_mask = 0;
u16 m_eeprom_read_mask = 0;
u32 m_eeprom_status_mask = 0;
bool m_eeprom_write_status = false;
void LoadFileToROM(const std::string& filename); void LoadFileToROM(const std::string& filename);
void LoadFileToEEPROM(const std::string& filename); void LoadFileToEEPROM(const std::string& filename);