Add save commands for SRAM/FRAM. Improve EEPROM.

Handle possible endian file read issues at file access time instead of
using Swap64 on every access.
Code comments and clean up.
This commit is contained in:
greyrogue 2015-02-13 07:41:21 -05:00 committed by GreyRogue
parent 9761df422a
commit 2d4aa2a195
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)
{
// Technically one of EEPROM, Flash, SRAM, FRAM
File::IOFile pStream(filename, "rb");
if (pStream)
{
@ -98,9 +99,31 @@ void CEXIAgp::LoadFileToEEPROM(const std::string& filename)
m_eeprom_mask = (m_eeprom_size - 1);
m_eeprom.resize(m_eeprom_size);
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)
@ -108,47 +131,60 @@ void CEXIAgp::SaveFileFromEEPROM(const std::string& filename)
File::IOFile pStream(filename, "wb");
if (pStream)
{
pStream.WriteBytes(m_eeprom.data(), m_eeprom_size);
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);
}
}
}
u32 CEXIAgp::ImmRead(u32 _uSize)
{
// We don't really care about _uSize
(void)_uSize;
u32 uData = 0;
u8 RomVal1, RomVal2, RomVal3, RomVal4;
switch (m_current_cmd)
{
case 0xAE000000:
case 0xAE000000: // Clock handshake?
uData = 0x5AAA5517; // 17 is precalculated hash
m_current_cmd = 0;
break;
case 0xAE010000:
case 0xAE010000: // Init?
uData = (m_return_pos == 0) ? 0x01020304 : 0xF0020304; // F0 is precalculated hash, 020304 is left over
if (m_return_pos == 1)
m_current_cmd = 0;
else
m_return_pos = 1;
break;
case 0xAE020000:
if (m_rw_offset == 0x8000000)
case 0xAE020000: // Read 2 bytes with 24 bit address
if (m_eeprom_write_status && ((m_rw_offset & m_eeprom_status_mask) == m_eeprom_status_mask) && (m_eeprom_status_mask != 0))
{
RomVal1 = 0x0;
RomVal2 = 0x1;
RomVal1 = 0x1;
RomVal2 = 0x0;
}
else
{
RomVal1 = m_rom[m_rw_offset++];
RomVal2 = m_rom[m_rw_offset++];
RomVal1 = m_rom[(m_rw_offset++) & m_rom_mask];
RomVal2 = m_rom[(m_rw_offset++) & m_rom_mask];
}
CRC8(&RomVal2, 1);
CRC8(&RomVal1, 1);
uData = (RomVal2 << 24) | (RomVal1 << 16) | (m_hash << 8);
m_current_cmd = 0;
break;
case 0xAE030000:
case 0xAE030000: // read the next 4 bytes out of 0x10000 group
if (_uSize == 1)
{
uData = 0xFF000000;
@ -156,10 +192,10 @@ u32 CEXIAgp::ImmRead(u32 _uSize)
}
else
{
RomVal1 = m_rom[m_rw_offset++];
RomVal2 = m_rom[m_rw_offset++];
RomVal3 = m_rom[m_rw_offset++];
RomVal4 = m_rom[m_rw_offset++];
RomVal1 = m_rom[(m_rw_offset++) & m_rom_mask];
RomVal2 = m_rom[(m_rw_offset++) & m_rom_mask];
RomVal3 = m_rom[(m_rw_offset++) & m_rom_mask];
RomVal4 = m_rom[(m_rw_offset++) & m_rom_mask];
CRC8(&RomVal2, 1);
CRC8(&RomVal1, 1);
CRC8(&RomVal4, 1);
@ -167,8 +203,25 @@ u32 CEXIAgp::ImmRead(u32 _uSize)
uData = (RomVal2 << 24) | (RomVal1 << 16) | (RomVal4 << 8) | (RomVal3);
}
break;
case 0xAE0B0000:
RomVal1 = m_eeprom_pos < 4 ? 0xA : (((u64*)m_eeprom.data())[(m_eeprom_cmd >> 1) & 0x3F] >> (m_eeprom_pos - 4)) & 0x1;
case 0xAE040000: // read 1 byte from 16 bit address
// 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;
CRC8(&RomVal2, 1);
CRC8(&RomVal1, 1);
@ -176,7 +229,8 @@ u32 CEXIAgp::ImmRead(u32 _uSize)
m_eeprom_pos++;
m_current_cmd = 0;
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;
m_current_cmd = 0;
break;
@ -191,6 +245,7 @@ u32 CEXIAgp::ImmRead(u32 _uSize)
void CEXIAgp::ImmWrite(u32 _uData, u32 _uSize)
{
// 0x00 = Execute current command?
if ((_uSize == 1) && ((_uData & 0xFF000000) == 0))
return;
@ -199,9 +254,10 @@ void CEXIAgp::ImmWrite(u32 _uData, u32 _uSize)
INFO_LOG(EXPANSIONINTERFACE, "AGP command %x", _uData);
switch (m_current_cmd)
{
case 0xAE020000:
case 0xAE030000:
m_rw_offset = ((_uData & 0xFFFFFF00) >> 7) & m_rom_mask;
case 0xAE020000: // set up 24 bit address for read 2 bytes
case 0xAE030000: // set up 24 bit address for read (0x10000 byte group)
// 25 bit address shifted one bit right = 24 bits
m_rw_offset = ((_uData & 0xFFFFFF00) >> (8 - 1));
m_return_pos = 0;
HashCmd = (_uData & 0xFF000000) >> 24;
CRC8(&HashCmd, 1);
@ -210,20 +266,45 @@ void CEXIAgp::ImmWrite(u32 _uData, u32 _uSize)
HashCmd = (_uData & 0x0000FF00) >> 8;
CRC8(&HashCmd, 1);
break;
case 0xAE0C0000:
if ((m_eeprom_pos < 0x8) || (m_eeprom_pos == ((m_eeprom_cmd & EE_READ) ? 0x8 : 0x48)))
case 0xAE040000: // set up 16 bit address for read 1 byte
// 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)
m_eeprom_cmd |= Mask;
else
m_eeprom_cmd &= ~Mask;
if (m_eeprom_pos == 0x48)
((u64*)(m_eeprom.data()))[(m_eeprom_cmd >> 1) & 0x3F] = m_eeprom_data;
if (m_eeprom_pos == m_eeprom_add_end + EE_DATA_BITS)
{
// 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
{
Mask = (u64)(1 << (0x47 - m_eeprom_pos));
Mask = (1ULL << (m_eeprom_add_end + EE_DATA_BITS - 1 - m_eeprom_pos));
if ((_uData >> 16) & 0x1)
m_eeprom_data |= Mask;
else
@ -237,13 +318,17 @@ void CEXIAgp::ImmWrite(u32 _uData, u32 _uSize)
CRC8(&HashCmd, 1);
break;
case 0xAE0B0000:
m_eeprom_write_status = false;
break;
case 0xAE000000:
case 0xAE010000:
case 0xAE090000:
case 0xAE0A0000:
default:
case 0xAE090000: // start DMA
m_eeprom_write_status = false; //ToDo: Verify with hardware which commands disable EEPROM CS
// Fall-through intentional
case 0xAE0A0000: // end DMA
m_eeprom_pos = 0;
// Fall-through intentional
default:
m_current_cmd = _uData;
m_return_pos = 0;
m_hash = 0xFF;
@ -264,6 +349,11 @@ void CEXIAgp::DoState(PointerWrap &p)
p.Do(m_eeprom_mask);
p.Do(m_eeprom_pos);
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_position);
p.Do(m_return_pos);

View File

@ -23,7 +23,10 @@ public:
private:
enum
{
EE_READ = 0x80
EE_IGNORE_BITS = 0x4,
EE_DATA_BITS = 0x40,
EE_READ_FALSE = 0xA,
EE_READ_TRUE = 0xB,
};
int m_slot;
@ -41,8 +44,13 @@ private:
u32 m_address = 0;
u32 m_rw_offset = 0;
u64 m_eeprom_data = 0;
u8 m_eeprom_pos = 0;
u16 m_eeprom_cmd = 0;
u16 m_eeprom_pos = 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 LoadFileToEEPROM(const std::string& filename);