#include "ameteor/flash.hpp"
#include "globals.hpp"
#include <cstring>
#include <fstream>
namespace AMeteor
{
Flash::Flash (bool big) :
CartMem(),
m_state(NORMAL)
{
if (big)
{
m_device_id = 0x13;
m_manufacturer_id = 0x62;
m_size = 128*1024;
}
else
{
m_device_id = 0x1B;
m_manufacturer_id = 0x32;
m_size = 64*1024;
}
*(uint32_t*)(m_data+MAX_SIZE) = m_size;
}
void Flash::Reset ()
{
std::memset(m_data, 0, m_size);
}
bool Flash::Load (std::istream& f)
{
f.read((char*)m_data, m_size);
return f.good();
}
bool Flash::Save (std::ostream& f)
{
f.write((char*)m_data, m_size);
return f.good();
}
uint8_t Flash::Read (uint16_t add)
{
switch (m_state)
{
case NORMAL:
return m_data[add];
case ID:
switch (add)
{
case 0: return m_manufacturer_id;
case 1: return m_device_id;
default: return 0;
}
default:
return 0;
}
}
bool Flash::Write (uint16_t add, uint8_t val)
{
switch (m_state)
{
case ID:
case NORMAL:
if (add == 0x5555 && val == 0xAA)
m_state = CMD1;
else
m_state = NORMAL;
break;
case CMD1:
if (add == 0x2AAA && val == 0x55)
m_state = CMD2;
else
m_state = NORMAL;
break;
case CMD2:
if (add == 0x5555)
switch (val)
{
case 0x80:
m_state = ERASE1;
break;
case 0x90:
m_state = ID;
break;
case 0xA0:
m_state = WRITE;
break;
case 0xF0:
m_state = NORMAL;
break;
default:
m_state = NORMAL;
break;
}
else
m_state = NORMAL;
break;
case ERASE1:
if (add == 0x5555 && val == 0xAA)
m_state = ERASE2;
else
m_state = NORMAL;
break;
case ERASE2:
if (add == 0x2AAA && val == 0x55)
m_state = ERASE3;
else
m_state = NORMAL;
break;
case ERASE3:
switch (val)
{
case 0x10:
if (add == 0x5555)
memset(m_data, 0xFF, m_size);
m_state = NORMAL;
break;
case 0x30:
if (!(add & 0x0FFF))
memset(m_data+add, 0xFF, 0x1000);
m_state = NORMAL;
break;
default:
m_state = NORMAL;
break;
}
break;
case WRITE:
m_data[add] &= val;
m_state = NORMAL;
return true;
}
return false;
}
bool Flash::SaveState (std::ostream& stream)
{
SS_WRITE_VAR(m_state);
SS_WRITE_DATA(m_data, m_size);
return true;
}
bool Flash::LoadState (std::istream& stream)
{
SS_READ_VAR(m_state);
SS_READ_DATA(m_data, m_size);
return true;
}
}