bsnes/higan/ws/eeprom/eeprom.cpp

142 lines
3.0 KiB
C++

#include <ws/ws.hpp>
namespace WonderSwan {
#include "serialization.cpp"
auto EEPROM::name() const -> string { return _name; }
auto EEPROM::data() -> uint16* { return _data; }
auto EEPROM::size() const -> uint { return _size; }
auto EEPROM::setName(string name) -> void {
_name = name;
}
auto EEPROM::setSize(uint size) -> void {
_size = bit::round(size);
}
auto EEPROM::erase() -> void {
for(auto& word : _data) word = 0xffff;
}
auto EEPROM::power() -> void {
r.latch = 0;
r.address = 0;
r.unknown = false;
r.writeRequested = false;
r.readRequested = false;
r.writeCompleted = true; //hack: should require time to complete reads/writes
r.readCompleted = true; //instead; leave bits always set so games don't lock
r.writeProtect = true;
}
auto EEPROM::read(uint port) -> uint8 {
if(!_size) return 0x00;
if(port == DataLo) return r.latch.byte(0);
if(port == DataHi) return r.latch.byte(1);
if(port == AddressLo) return r.address.byte(0);
if(port == AddressHi) return r.address.byte(1);
if(port == Status) return (
1 << 7
| r.unknown << 6
| r.writeRequested << 5
| r.readRequested << 4
| r.writeCompleted << 1
| r.readCompleted << 0
);
return 0x00;
}
auto EEPROM::write(uint port, uint8 data) -> void {
if(!_size) return;
if(port == DataLo) {
r.latch.byte(0) = data;
return;
}
if(port == DataHi) {
r.latch.byte(1) = data;
return;
}
if(port == AddressLo) {
r.address.byte(0) = data;
return;
}
if(port == AddressHi) {
r.address.byte(1) = data;
return;
}
if(port == Command) {
r.unknown = data.bit(6);
r.writeRequested = data.bit(5);
r.readRequested = data.bit(4);
execute();
return;
}
}
auto EEPROM::execute() -> void {
auto bits = bit::first(_size);
auto address = r.address.bits(0, bits - 1);
auto special = r.address.bits(bits - 2, bits - 1);
auto command = r.address.bits(bits, bits + 1);
auto start = r.address.bit(bits + 2);
if(!start) return;
//write disable
if(command == 0 && special == 0) {
r.writeProtect = true;
}
//write all
if(command == 0 && special == 1 && !r.writeProtect) {
for(auto n : range(_size)) _data[n] = r.latch;
}
//erase all
if(command == 0 && special == 2 && !r.writeProtect) {
for(auto n : range(_size)) _data[n] = 0xffff;
}
//write enable
if(command == 0 && special == 3) {
r.writeProtect = false;
}
//write word
if(command == 1 && r.writeRequested && !r.writeProtect) {
_data[address] = r.latch;
r.writeRequested = false;
r.writeCompleted = true;
}
//read word
if(command == 2 && r.readRequested) {
r.latch = _data[address];
r.readRequested = false;
r.readCompleted = true;
}
//erase word
if(command == 3 && r.writeRequested && !r.writeProtect) {
_data[address] = 0xffff;
r.writeRequested = false;
r.writeCompleted = true;
}
}
auto EEPROM::operator[](uint10 addr) -> uint16& {
return _data[addr];
}
}