Update to v106r63 release.

byuu says:
Changelog:

  - gb/mbc7: rewrote the 93LCx6 EEPROM emulation
  - sfc/slot/bsmemory: rewrote the flash emulation for Satellaview
    cartridges

As of this release, flash-based BS Memory cartridges will be writable.
So without the bsnes patch to disable write limits, some games will lock
out after a few plays.
This commit is contained in:
Tim Allen 2018-09-11 21:16:58 +10:00
parent c2d0ed4ca8
commit c58169945c
12 changed files with 272 additions and 248 deletions

View File

@ -28,13 +28,13 @@ using namespace nall;
namespace Emulator {
static const string Name = "higan";
static const string Version = "106.62";
static const string Version = "106.63";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "https://byuu.org/";
//incremented only when serialization format changes
static const string SerializerVersion = "106.44";
static const string SerializerVersion = "106.63";
namespace Constants {
namespace Colorburst {

View File

@ -5,31 +5,30 @@
auto Cartridge::MBC7::EEPROM::load(Markup::Node document) -> void {
for(auto& byte : data) byte = 0xff;
size = 4096; //EEPROM size is in bits
width = 16; //16-bit configuration
size = 512; //EEPROM size is in bytes
width = 16; //16-bit configuration
if(auto memory = Emulator::Game::Memory{document["game/board/memory(type=EEPROM,content=Save)"]}) {
if(memory.size == 128) size = 1024; //manifest size is in bytes
if(memory.size == 256) size = 2048;
if(memory.size == 512) size = 4096;
if(memory.size == 128) size = 128;
if(memory.size == 256) size = 256;
if(memory.size == 512) size = 512;
if(auto fp = platform->open(cartridge.pathID(), memory.name(), File::Read, File::Optional)) {
fp->read(data, min(fp->size(), sizeof(data)));
}
}
command.length = 3;
if(size == 1024) address.length = width == 8 ? 6 : 7;
if(size == 2048) address.length = width == 8 ? 7 : 8;
if(size == 4096) address.length = width == 8 ? 8 : 9;
input.length = width;
output.length = 1 + width; //there is an extra zero dummy bit on reads
//note: the 93LC56 alone has an extra dummy address bit
if(size == 128) input.addressLength = width == 16 ? 6 : 7; //93LC46
if(size == 256) input.addressLength = width == 16 ? 8 : 9; //93LC56
if(size == 512) input.addressLength = width == 16 ? 8 : 9; //93LC66
input.dataLength = width;
}
auto Cartridge::MBC7::EEPROM::save(Markup::Node document) -> void {
if(auto memory = Emulator::Game::Memory{document["game/board/memory(type=EEPROM,content=Save)"]}) {
if(auto fp = platform->open(cartridge.pathID(), memory.name(), File::Write)) {
fp->write(data, size >> 3); //bytes -> bits
fp->write(data, size);
}
}
}
@ -42,17 +41,12 @@ auto Cartridge::MBC7::EEPROM::main() -> void {
if(busy) busy--;
}
auto Cartridge::MBC7::EEPROM::power(bool reset) -> void {
if(!reset) {
select = 0;
writable = 0;
}
auto Cartridge::MBC7::EEPROM::power() -> void {
select = 0;
clock = 0;
writable = 0;
busy = 0;
command.flush();
address.flush();
input.flush();
output.flush();
}
@ -61,13 +55,13 @@ auto Cartridge::MBC7::EEPROM::readIO() -> uint8 {
uint8 data = 0b00'1111'00;
data.bit(7) = select;
data.bit(6) = clock;
data.bit(1) = 1;
data.bit(1) = input.edge();
if(!select) {
data.bit(0) = 1; //high-z when the chip is idle (not selected)
} else if(busy) {
data.bit(0) = 0; //low when a programming command is in progress
} else if(output.count) {
data.bit(0) = output.peek(); //shift register data during read commands
data.bit(0) = output.edge(); //shift register data during read commands
} else {
data.bit(0) = 1; //high-z during all other commands
}
@ -75,129 +69,118 @@ auto Cartridge::MBC7::EEPROM::readIO() -> uint8 {
}
auto Cartridge::MBC7::EEPROM::writeIO(uint8 data) -> void {
//bring chip out of idle state on rising CS edge
if(select.raise(data.bit(7))) return power(true);
//chip enters idle state on falling CS edge
if(select && !data.bit(7)) return power();
//do nothing if chip is idle
if(!select) return;
//chip leaves idle state on rising CS edge
if(!(select = data.bit(7))) return;
//shift register clocks on rising edge
//input shift register clocks on rising edge
if(!clock.raise(data.bit(6))) return;
//sequential read mode
//read mode
if(output.count && !data.bit(1)) {
output.read();
if(output.count == 0) {
address.value++;
read();
if(input.start() && *input.start() == 1) {
if(input.opcode() && *input.opcode() == 0b10) {
output.read();
if(output.count == 0) {
//sequential read mode
input.increment();
read();
}
}
}
return;
}
output.flush();
//wait for start bit to be set
if(command.count == 0 && !data.bit(1)) return;
input.write(data.bit(1));
//waiting on command?
if(command.count < command.length) {
command.write(data.bit(1));
if(command.count < command.length) return;
//wait for start
if(!input.start()) return;
uint start = *input.start();
return address.flush();
}
//waiting on address bits?
if(address.count < address.length) {
address.write(data.bit(1));
if(address.count < address.length) return;
uint3 opcode = command.bits(0, command.length - 1);
if(opcode == 0b100) {
uint2 mode = address.bits(address.length - 2, address.length - 1);
if(mode == 0b00) return writeDisable();
if(mode == 0b01) return input.flush(); //writeAll
if(mode == 0b10) return eraseAll();
if(mode == 0b11) return writeEnable();
}
if(opcode == 0b101) return input.flush(); //write
if(opcode == 0b110) return read();
if(opcode == 0b111) return erase();
return;
}
//waiting on data bits from a write or writeAll command?
if(input.count < input.length) { //block new commands and inputs until the next clock edge
input.write(data.bit(1));
if(input.count < input.length) return;
uint3 opcode = command.bits(0, command.length - 1);
if(opcode == 0b101) return write();
if(opcode == 0b100) return writeAll();
return;
//start bit must be set
if(start != 1) return input.flush();
//wait for opcode
if(!input.opcode()) return;
uint opcode = *input.opcode();
//wait for address
if(!input.address()) return;
if(opcode == 0b00) {
auto mode = *input.mode();
if(mode == 0b00) return writeDisable();
if(mode == 0b01) return writeAll();
if(mode == 0b10) return eraseAll();
if(mode == 0b11) return writeEnable();
}
if(opcode == 0b01) return write();
if(opcode == 0b10) return read();
if(opcode == 0b11) return erase();
}
//
auto Cartridge::MBC7::EEPROM::read() -> void {
command.flush();
auto address = this->address.value << (width == 16) & (size >> 3) - 1;
output.value = 0;
if(width >= 8) output.value |= data[address++] << 8;
if(width >= 16) output.value |= data[address++] << 0;
output.count = output.length;
uint address = *input.address() << (width == 16) & size - 1;
output.flush();
for(uint4 index : range(width)) {
output.write(data[address + !index.bit(3)].bit(index.bits(0,2)));
}
output.write(0); //reads have an extra dummy data bit
}
auto Cartridge::MBC7::EEPROM::write() -> void {
command.flush();
if(!writable) return;
auto address = this->address.value << (width == 16) & (size >> 3) - 1;
if(width >= 8) data[address++] = input.value >> 8;
if(width >= 16) data[address++] = input.value >> 0;
input.flush();
busy = 4; //ms
if(!input.data()) return; //wait for data
if(!writable) return input.flush();
uint address = *input.address() << (width == 16) & size - 1;
for(uint4 index : range(width)) {
data[address + !index.bit(3)].bit(index.bits(0,2)) = input.read();
}
busy = 4; //milliseconds
return input.flush();
}
auto Cartridge::MBC7::EEPROM::erase() -> void {
command.flush();
if(!writable) return;
auto address = this->address.value << (width == 16) & (size >> 3) - 1;
if(width >= 8) data[address++] = 0xff;
if(width >= 16) data[address++] = 0xff;
busy = 4; //ms
if(!writable) return input.flush();
uint address = *input.address() << (width == 16) & size - 1;
for(uint index : range(width)) {
data[address + index / 8].bit(index % 8) = 1;
}
busy = 4; //milliseconds
return input.flush();
}
auto Cartridge::MBC7::EEPROM::writeAll() -> void {
command.flush();
if(!writable) return;
uint8 lo = input.byte(0);
uint8 hi = input.byte(width == 16);
if(!input.data()) return; //wait for data
if(!writable) return input.flush();
auto word = *input.data();
for(uint address = 0; address < 512;) {
data[address++] = hi;
data[address++] = lo;
data[address++] = word.byte(width == 16);
data[address++] = word.byte(0);
}
input.flush();
busy = 16; //ms
busy = 16; //milliseconds
return input.flush();
}
auto Cartridge::MBC7::EEPROM::eraseAll() -> void {
command.flush();
if(!writable) return;
for(uint address; address < 512;) {
data[address++] = 0xff;
data[address++] = 0xff;
}
busy = 8; //ms
if(!writable) return input.flush();
for(auto& byte : data) byte = 0xff;
busy = 8; //milliseconds
return input.flush();
}
auto Cartridge::MBC7::EEPROM::writeEnable() -> void {
command.flush();
writable = true;
return input.flush();
}
auto Cartridge::MBC7::EEPROM::writeDisable() -> void {
command.flush();
writable = false;
return input.flush();
}
//
@ -207,20 +190,50 @@ auto Cartridge::MBC7::EEPROM::ShiftRegister::flush() -> void {
count = 0;
}
//read the current bit in the shift register without clocking it
auto Cartridge::MBC7::EEPROM::ShiftRegister::peek() -> bool {
return value.bit(length - 1);
auto Cartridge::MBC7::EEPROM::ShiftRegister::edge() -> uint1 {
return value.bit(0);
}
auto Cartridge::MBC7::EEPROM::ShiftRegister::read() -> bool {
bool bit = value.bit(length - 1);
value <<= 1;
if(count) count--;
auto Cartridge::MBC7::EEPROM::ShiftRegister::read() -> uint1 {
uint1 bit = value.bit(0);
value >>= 1;
count--;
return bit;
}
auto Cartridge::MBC7::EEPROM::ShiftRegister::write(bool bit) -> void {
auto Cartridge::MBC7::EEPROM::ShiftRegister::write(uint1 bit) -> void {
value <<= 1;
value |= bit;
value.bit(0) = bit;
count++;
}
//
auto Cartridge::MBC7::EEPROM::InputShiftRegister::start() -> maybe<uint1> {
if(count < 1) return {};
return {value >> count - 1 & 1};
}
auto Cartridge::MBC7::EEPROM::InputShiftRegister::opcode() -> maybe<uint2> {
if(count < 1 + 2) return {};
return {value >> count - 3 & 3};
}
auto Cartridge::MBC7::EEPROM::InputShiftRegister::mode() -> maybe<uint2> {
if(count < 1 + 2 + addressLength) return {};
return {value >> count - 5 & 3};
}
auto Cartridge::MBC7::EEPROM::InputShiftRegister::address() -> maybe<uint9> {
if(count < 1 + 2 + addressLength) return {};
return {value >> count - (3 + addressLength) & (1 << addressLength) - 1};
}
auto Cartridge::MBC7::EEPROM::InputShiftRegister::data() -> maybe<uint16> {
if(count < 1 + 2 + addressLength + dataLength) return {};
return {value >> count - (3 + addressLength + dataLength) & (1 << dataLength) - 1};
}
auto Cartridge::MBC7::EEPROM::InputShiftRegister::increment() -> void {
value.bits(0, addressLength - 1)++;
}

View File

@ -1,5 +1,5 @@
struct MBC7 : Mapper {
enum : uint { Center = 0x81d0 };
enum : uint { Center = 0x81d0 }; //not 0x8000
//mbc7.cpp
auto load(Markup::Node document) -> void override;
@ -17,7 +17,7 @@ struct MBC7 : Mapper {
auto load(Markup::Node document) -> void;
auto save(Markup::Node document) -> void;
auto main() -> void;
auto power(bool reset = false) -> void;
auto power() -> void;
//Game Boy MBC7 interface
auto readIO() -> uint8;
@ -36,9 +36,9 @@ struct MBC7 : Mapper {
auto serialize(serializer&) -> void;
//it is awkward no matter if data is uint1[4096], uint8[512], or uint16[256]
uint8 data[512]; //uint8 was chosen solely for easier serialization and saving
uint size; //in bits; not bytes
uint width; //8-bit (ORG=0) or 16-bit (ORG=1) configuration
uint8 data[512]; //uint8 was chosen solely for easier serialization and saving
uint size; //in bytes
uint width; //8-bit (ORG=0) or 16-bit (ORG=1) configuration
boolean select; //CS
boolean clock; //CLK
@ -46,21 +46,34 @@ struct MBC7 : Mapper {
uint busy; //busy cycles in milliseconds remaining for programming (write) operations to complete
struct ShiftRegister {
auto bit(uint index) { return value.bit(index); }
auto bits(uint lo, uint hi) { return value.bits(lo, hi); }
auto byte(uint index) { return value.byte(index); }
auto flush() -> void;
auto peek() -> bool;
auto read() -> bool;
auto write(bool data) -> void;
auto edge() -> uint1;
auto read() -> uint1;
auto write(uint1 data) -> void;
uint32 value;
uint32 count;
};
struct InputShiftRegister : ShiftRegister {
auto start() -> maybe<uint1>;
auto opcode() -> maybe<uint2>;
auto mode() -> maybe<uint2>;
auto address() -> maybe<uint9>;
auto data() -> maybe<uint16>;
auto increment() -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
uint32 value;
uint32 count;
uint32 length;
} command, address, input, output;
uint32 addressLength;
uint32 dataLength;
} input;
struct OutputShiftRegister : ShiftRegister {
//serialization.cpp
auto serialize(serializer&) -> void;
} output;
} eeprom;
struct IO {

View File

@ -15,14 +15,18 @@ auto Cartridge::MBC7::EEPROM::serialize(serializer& s) -> void {
s.boolean(clock);
s.boolean(writable);
s.integer(busy);
command.serialize(s);
address.serialize(s);
input.serialize(s);
output.serialize(s);
}
auto Cartridge::MBC7::EEPROM::ShiftRegister::serialize(serializer& s) -> void {
auto Cartridge::MBC7::EEPROM::InputShiftRegister::serialize(serializer& s) -> void {
s.integer(value);
s.integer(count);
s.integer(addressLength);
s.integer(dataLength);
}
auto Cartridge::MBC7::EEPROM::OutputShiftRegister::serialize(serializer& s) -> void {
s.integer(value);
s.integer(count);
s.integer(length);
}

View File

@ -77,7 +77,7 @@ auto Cartridge::loadCartridgeGameBoy(Markup::Node node) -> void {
auto Cartridge::loadCartridgeBSMemory(Markup::Node node) -> void {
if(auto memory = Emulator::Game::Memory{node["game/board/memory(content=Program)"]}) {
bsmemory.readonly = memory.type == "ROM";
bsmemory.ROM = memory.type == "ROM";
bsmemory.memory.allocate(memory.size);
if(auto fp = platform->open(bsmemory.pathID, memory.name(), File::Read, File::Required)) {
fp->read(bsmemory.memory.data(), memory.size);

View File

@ -22,11 +22,17 @@ auto MCC::power() -> void {
w.exEnableLo = 1;
w.exEnableHi = 0;
w.exMapping = 1;
w.bsWritable = 0;
w.unknown = 0;
w.bsQueryable = 0;
w.bsFlashable = 0;
x.enable = 0;
x.value = 0b0011'1111;
memory::copy(&r, &w, sizeof(Registers));
x.value = 0b00111111;
commit();
}
auto MCC::commit() -> void {
r = w; //memory::copy(&r, &w, sizeof(Registers));
bsmemory.queryable(r.bsQueryable);
bsmemory.flashable(r.bsFlashable);
}
auto MCC::read(uint24 address, uint8 data) -> uint8 {
@ -46,8 +52,8 @@ auto MCC::read(uint24 address, uint8 data) -> uint8 {
case 9: return r.exEnableLo << 7;
case 10: return r.exEnableHi << 7;
case 11: return r.exMapping << 7;
case 12: return r.bsWritable << 7;
case 13: return r.unknown << 7;
case 12: return r.bsQueryable << 7;
case 13: return r.bsFlashable << 7;
case 14: return 0; //commit (always zero)
case 15: return 0; //x.enable (always zero)
}
@ -72,9 +78,9 @@ auto MCC::write(uint24 address, uint8 data) -> void {
case 9: w.exEnableLo = data.bit(7); break;
case 10: w.exEnableHi = data.bit(7); break;
case 11: w.exMapping = data.bit(7); break;
case 12: w.bsWritable = data.bit(7); break;
case 13: w.unknown = data.bit(7); break;
case 14: if(data.bit(7)) memory::copy(&r, &w, sizeof(Registers)); break;
case 12: w.bsQueryable = data.bit(7); break;
case 13: w.bsFlashable = data.bit(7); break;
case 14: if(data.bit(7)) commit(); break;
case 15: x.enable = data.bit(7); break;
}
}

View File

@ -8,6 +8,7 @@ struct MCC {
//mcc.cpp
auto unload() -> void;
auto power() -> void;
auto commit() -> void;
auto read(uint24 address, uint8 data) -> uint8;
auto write(uint24 address, uint8 data) -> void;
@ -40,8 +41,8 @@ private:
uint1 exEnableLo; //bit 9
uint1 exEnableHi; //bit 10
uint1 exMapping; //bit 11
uint1 bsWritable; //bit 12
uint1 unknown; //bit 13
uint1 bsQueryable; //bit 12
uint1 bsFlashable; //bit 13
} r, w;
//bit 14 (commit)

View File

@ -11,8 +11,8 @@ auto MCC::serialize(serializer& s) -> void {
s.integer(r.exEnableLo);
s.integer(r.exEnableHi);
s.integer(r.exMapping);
s.integer(r.bsWritable);
s.integer(r.unknown);
s.integer(r.bsQueryable);
s.integer(r.bsFlashable);
s.integer(w.mapping);
s.integer(w.psramEnableLo);
s.integer(w.psramEnableHi);
@ -22,8 +22,8 @@ auto MCC::serialize(serializer& s) -> void {
s.integer(w.exEnableLo);
s.integer(w.exEnableHi);
s.integer(w.exMapping);
s.integer(w.bsWritable);
s.integer(w.unknown);
s.integer(w.bsQueryable);
s.integer(w.bsFlashable);
s.integer(x.enable);
s.integer(x.value);
}

View File

@ -6,7 +6,8 @@ namespace SuperFamicom {
BSMemory bsmemory;
auto BSMemory::load() -> void {
if(!memory.size()) memory.allocate(1024 * 1024);
queryable(true);
flashable(true);
}
auto BSMemory::unload() -> void {
@ -14,14 +15,8 @@ auto BSMemory::unload() -> void {
}
auto BSMemory::power() -> void {
regs.command = 0;
regs.writeOld = 0x00;
regs.writeNew = 0x00;
regs.flashEnable = false;
regs.readEnable = false;
regs.writeEnable = false;
memory.writable(regs.writeEnable);
memory.writable(false);
io = {};
}
auto BSMemory::data() -> uint8* {
@ -32,92 +27,71 @@ auto BSMemory::size() const -> uint {
return memory.size();
}
auto BSMemory::read(uint24 addr, uint8 data) -> uint8 {
if(readonly) {
return memory.read(bus.mirror(addr, memory.size()), data);
auto BSMemory::read(uint24 address, uint8 data) -> uint8 {
if(!size()) return data;
address = bus.mirror(address, size());
if(!pin.queryable) return memory.read(address, data);
if(io.mode == 0x70) {
return 0x80;
}
if(addr == 0x0002) {
if(regs.flashEnable) return 0x80;
if(io.mode == 0x71) {
if((uint16)address == 0x0002) return 0x80;
if((uint16)address == 0x0004) return 0x87;
if((uint16)address == 0x0006) return 0x00; //unknown purpose (not always zero)
return 0x00;
}
if(addr == 0x5555) {
if(regs.flashEnable) return 0x80;
if(io.mode == 0x75) {
if((uint8)address == 0x00) return 0x4d; //'M' (memory)
if((uint8)address == 0x02) return 0x50; //'P' (pack)
if((uint8)address == 0x04) return 0x04; //unknown purpose
if((uint8)address == 0x06) return Type << 4 | (uint4)log2(size() >> 10);
return random(); //not actually random, but not ROM data either, yet varies per cartridge
}
if(regs.readEnable && addr >= 0xff00 && addr <= 0xff13) {
//read flash cartridge vendor information
switch(addr - 0xff00) {
case 0x00: return 0x4d;
case 0x01: return 0x00;
case 0x02: return 0x50;
case 0x03: return 0x00;
case 0x04: return 0x00;
case 0x05: return 0x00;
case 0x06: return 0x2a; //0x2a = 8mbit, 0x2b = 16mbit (not known to exist, though BIOS recognizes ID)
case 0x07: return 0x00;
default: return 0x00;
}
}
return memory.read(bus.mirror(addr, memory.size()), data);
return memory.read(address, data);
}
auto BSMemory::write(uint24 addr, uint8 data) -> void {
if(readonly) {
auto BSMemory::write(uint24 address, uint8 data) -> void {
if(!size() || !pin.queryable) return;
address = bus.mirror(address, size());
//write byte
if(io.mode == 0x10 || io.mode == 0x40) {
if(!pin.flashable) return;
memory.writable(true);
memory.write(address, memory.read(address) & data); //writes can only clear bits
memory.writable(false);
io.mode = 0x70;
return;
}
if((addr & 0xff0000) == 0) {
regs.writeOld = regs.writeNew;
regs.writeNew = data;
if(regs.writeEnable && regs.writeOld == regs.writeNew) {
return memory.write(addr, data);
}
} else {
if(regs.writeEnable) {
return memory.write(addr, data);
}
//erase 64KB page
if(io.mode == 0x20) {
//completes even if !pin.flashable
memory.writable(true);
for(uint offset : range(1 << 16)) memory.write(address & 0xff0000 | offset, 0xff);
memory.writable(false);
io.mode = 0x70;
return;
}
if(addr == 0x0000) {
regs.command <<= 8;
regs.command |= data;
//erase all pages
if(io.mode == 0xa7) {
//completes even if !pin.flashable
if(Type == 3) return; //Type 3 doesn't support this command
if((regs.command & 0xffff) == 0x38d0) {
regs.flashEnable = true;
regs.readEnable = true;
}
memory.writable(true);
for(uint offset : range(size())) memory.write(offset, 0xff);
memory.writable(false);
io.mode = 0x70;
return;
}
if(addr == 0x2aaa) {
regs.command <<= 8;
regs.command |= data;
}
if(addr == 0x5555) {
regs.command <<= 8;
regs.command |= data;
if((regs.command & 0xffffff) == 0xaa5570) {
regs.writeEnable = false;
}
if((regs.command & 0xffffff) == 0xaa55a0) {
regs.writeOld = 0x00;
regs.writeNew = 0x00;
regs.flashEnable = true;
regs.writeEnable = true;
}
if((regs.command & 0xffffff) == 0xaa55f0) {
regs.flashEnable = false;
regs.readEnable = false;
regs.writeEnable = false;
}
memory.writable(regs.writeEnable);
if((uint16)address == 0x0000) {
io.mode = data;
}
}

View File

@ -1,4 +1,7 @@
struct BSMemory : Memory {
auto queryable(bool queryable) { pin.queryable = !ROM && queryable; }
auto flashable(bool flashable) { pin.flashable = !ROM && flashable; }
//bsmemory.cpp
auto load() -> void;
auto unload() -> void;
@ -6,26 +9,33 @@ struct BSMemory : Memory {
auto data() -> uint8* override;
auto size() const -> uint override;
auto read(uint24 addr, uint8 data) -> uint8 override;
auto write(uint24 addr, uint8 data) -> void override;
auto read(uint24 address, uint8 data) -> uint8 override;
auto write(uint24 address, uint8 data) -> void override;
//serialization.cpp
auto serialize(serializer&) -> void;
uint pathID = 0;
//0 = Flash; 1 = MaskROM
uint ROM = 1;
//valid types are 1,2,3,4
//type 2 is currently unsupported
//type 1 is the only type to exist (all flash-based BS Memory Cassettes are type 1)
uint Type = 1;
ProtectableMemory memory;
bool readonly;
private:
struct {
uint command;
uint8 writeOld;
uint8 writeNew;
struct Pin {
uint1 queryable;
uint1 flashable;
} pin;
bool flashEnable;
bool readEnable;
bool writeEnable;
} regs;
struct IO {
uint8 mode;
} io;
};
extern BSMemory bsmemory;

View File

@ -1,3 +1,6 @@
auto BSMemory::serialize(serializer& s) -> void {
if(!readonly) s.array(memory.data(), memory.size());
if(!ROM) s.array(memory.data(), memory.size());
s.integer(pin.queryable);
s.integer(pin.flashable);
s.integer(io.mode);
}

View File

@ -17,7 +17,7 @@ using uint32 = Natural<32>;
using uint64 = Natural<64>;
struct FX {
auto open(vector<string>& arguments) -> bool;
auto open(vector<string> arguments) -> bool;
auto close() -> void;
auto readable() -> bool;
auto read() -> uint8_t;
@ -35,12 +35,12 @@ struct FX {
serial device;
};
auto FX::open(vector<string>& arguments) -> bool {
auto FX::open(vector<string> arguments) -> bool {
//device name override support
string name;
for(uint n : range(arguments)) {
if(arguments[n].beginsWith("--device=")) {
name = arguments.take(n).trimLeft("--device=", 1L);
for(auto argument : arguments) {
if(argument.beginsWith("--device=")) {
name = argument.trimLeft("--device=", 1L);
break;
}
}
@ -54,7 +54,7 @@ auto FX::open(vector<string>& arguments) -> bool {
while(true) {
while(readable()) read();
auto iplrom = read(0x2184, 122);
auto sha256 = Hash::SHA256(iplrom.data(), iplrom.size()).digest();
auto sha256 = Hash::SHA256(iplrom).digest();
if(sha256 == "41b79712a4a2d16d39894ae1b38cde5c41dad22eadc560df631d39f13df1e4b9") break;
}