mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-23 18:29:16 +00:00
Give autonomy to secondary slots.
This commit is contained in:
parent
68361913ee
commit
183cb519e7
@ -27,13 +27,13 @@ class ASCII16kbROMSlotHandler: public MemorySlotHandler {
|
|||||||
if(pc_is_outside_bios) {
|
if(pc_is_outside_bios) {
|
||||||
if(address == 0x6000) confidence_counter_.add_hit(); else confidence_counter_.add_equivocal();
|
if(address == 0x6000) confidence_counter_.add_hit(); else confidence_counter_.add_equivocal();
|
||||||
}
|
}
|
||||||
slot_.map(0, value * 0x4000, 0x4000, 0x4000);
|
slot_.map(value * 0x4000, 0x4000, 0x4000);
|
||||||
break;
|
break;
|
||||||
case 0xe:
|
case 0xe:
|
||||||
if(pc_is_outside_bios) {
|
if(pc_is_outside_bios) {
|
||||||
if(address == 0x7000 || address == 0x77ff) confidence_counter_.add_hit(); else confidence_counter_.add_equivocal();
|
if(address == 0x7000 || address == 0x77ff) confidence_counter_.add_hit(); else confidence_counter_.add_equivocal();
|
||||||
}
|
}
|
||||||
slot_.map(0, value * 0x4000, 0x8000, 0x4000);
|
slot_.map(value * 0x4000, 0x8000, 0x4000);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,25 +27,25 @@ class ASCII8kbROMSlotHandler: public MemorySlotHandler {
|
|||||||
if(pc_is_outside_bios) {
|
if(pc_is_outside_bios) {
|
||||||
if(address == 0x6000 || address == 0x60ff) confidence_counter_.add_hit(); else confidence_counter_.add_equivocal();
|
if(address == 0x6000 || address == 0x60ff) confidence_counter_.add_hit(); else confidence_counter_.add_equivocal();
|
||||||
}
|
}
|
||||||
slot_.map(0, value * 0x2000, 0x4000, 0x2000);
|
slot_.map(value * 0x2000, 0x4000, 0x2000);
|
||||||
break;
|
break;
|
||||||
case 0xd:
|
case 0xd:
|
||||||
if(pc_is_outside_bios) {
|
if(pc_is_outside_bios) {
|
||||||
if(address == 0x6800 || address == 0x68ff) confidence_counter_.add_hit(); else confidence_counter_.add_equivocal();
|
if(address == 0x6800 || address == 0x68ff) confidence_counter_.add_hit(); else confidence_counter_.add_equivocal();
|
||||||
}
|
}
|
||||||
slot_.map(0, value * 0x2000, 0x6000, 0x2000);
|
slot_.map(value * 0x2000, 0x6000, 0x2000);
|
||||||
break;
|
break;
|
||||||
case 0xe:
|
case 0xe:
|
||||||
if(pc_is_outside_bios) {
|
if(pc_is_outside_bios) {
|
||||||
if(address == 0x7000 || address == 0x70ff) confidence_counter_.add_hit(); else confidence_counter_.add_equivocal();
|
if(address == 0x7000 || address == 0x70ff) confidence_counter_.add_hit(); else confidence_counter_.add_equivocal();
|
||||||
}
|
}
|
||||||
slot_.map(0, value * 0x2000, 0x8000, 0x2000);
|
slot_.map(value * 0x2000, 0x8000, 0x2000);
|
||||||
break;
|
break;
|
||||||
case 0xf:
|
case 0xf:
|
||||||
if(pc_is_outside_bios) {
|
if(pc_is_outside_bios) {
|
||||||
if(address == 0x7800 || address == 0x78ff) confidence_counter_.add_hit(); else confidence_counter_.add_equivocal();
|
if(address == 0x7800 || address == 0x78ff) confidence_counter_.add_hit(); else confidence_counter_.add_equivocal();
|
||||||
}
|
}
|
||||||
slot_.map(0, value * 0x2000, 0xa000, 0x2000);
|
slot_.map(value * 0x2000, 0xa000, 0x2000);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,19 +27,19 @@ class KonamiROMSlotHandler: public MemorySlotHandler {
|
|||||||
if(pc_is_outside_bios) {
|
if(pc_is_outside_bios) {
|
||||||
if(address == 0x6000) confidence_counter_.add_hit(); else confidence_counter_.add_equivocal();
|
if(address == 0x6000) confidence_counter_.add_hit(); else confidence_counter_.add_equivocal();
|
||||||
}
|
}
|
||||||
slot_.map(0, value * 0x2000, 0x6000, 0x2000);
|
slot_.map(value * 0x2000, 0x6000, 0x2000);
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
if(pc_is_outside_bios) {
|
if(pc_is_outside_bios) {
|
||||||
if(address == 0x8000) confidence_counter_.add_hit(); else confidence_counter_.add_equivocal();
|
if(address == 0x8000) confidence_counter_.add_hit(); else confidence_counter_.add_equivocal();
|
||||||
}
|
}
|
||||||
slot_.map(0, value * 0x2000, 0x8000, 0x2000);
|
slot_.map(value * 0x2000, 0x8000, 0x2000);
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
if(pc_is_outside_bios) {
|
if(pc_is_outside_bios) {
|
||||||
if(address == 0xa000) confidence_counter_.add_hit(); else confidence_counter_.add_equivocal();
|
if(address == 0xa000) confidence_counter_.add_hit(); else confidence_counter_.add_equivocal();
|
||||||
}
|
}
|
||||||
slot_.map(0, value * 0x2000, 0xa000, 0x2000);
|
slot_.map(value * 0x2000, 0xa000, 0x2000);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,13 +29,13 @@ class KonamiWithSCCROMSlotHandler: public MemorySlotHandler {
|
|||||||
if(pc_is_outside_bios) {
|
if(pc_is_outside_bios) {
|
||||||
if(address == 0x5000) confidence_counter_.add_hit(); else confidence_counter_.add_equivocal();
|
if(address == 0x5000) confidence_counter_.add_hit(); else confidence_counter_.add_equivocal();
|
||||||
}
|
}
|
||||||
slot_.map(0, value * 0x2000, 0x4000, 0x2000);
|
slot_.map(value * 0x2000, 0x4000, 0x2000);
|
||||||
break;
|
break;
|
||||||
case 0x0e:
|
case 0x0e:
|
||||||
if(pc_is_outside_bios) {
|
if(pc_is_outside_bios) {
|
||||||
if(address == 0x7000) confidence_counter_.add_hit(); else confidence_counter_.add_equivocal();
|
if(address == 0x7000) confidence_counter_.add_hit(); else confidence_counter_.add_equivocal();
|
||||||
}
|
}
|
||||||
slot_.map(0, value * 0x2000, 0x6000, 0x2000);
|
slot_.map(value * 0x2000, 0x6000, 0x2000);
|
||||||
break;
|
break;
|
||||||
case 0x12:
|
case 0x12:
|
||||||
if(pc_is_outside_bios) {
|
if(pc_is_outside_bios) {
|
||||||
@ -43,10 +43,10 @@ class KonamiWithSCCROMSlotHandler: public MemorySlotHandler {
|
|||||||
}
|
}
|
||||||
if((value&0x3f) == 0x3f) {
|
if((value&0x3f) == 0x3f) {
|
||||||
scc_is_visible_ = true;
|
scc_is_visible_ = true;
|
||||||
slot_.unmap(0, 0x8000, 0x2000);
|
slot_.unmap(0x8000, 0x2000);
|
||||||
} else {
|
} else {
|
||||||
scc_is_visible_ = false;
|
scc_is_visible_ = false;
|
||||||
slot_.map(0, value * 0x2000, 0x8000, 0x2000);
|
slot_.map(value * 0x2000, 0x8000, 0x2000);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x13:
|
case 0x13:
|
||||||
@ -61,7 +61,7 @@ class KonamiWithSCCROMSlotHandler: public MemorySlotHandler {
|
|||||||
if(pc_is_outside_bios) {
|
if(pc_is_outside_bios) {
|
||||||
if(address == 0xb000) confidence_counter_.add_hit(); else confidence_counter_.add_equivocal();
|
if(address == 0xb000) confidence_counter_.add_hit(); else confidence_counter_.add_equivocal();
|
||||||
}
|
}
|
||||||
slot_.map(0, value * 0x2000, 0xa000, 0x2000);
|
slot_.map(value * 0x2000, 0xa000, 0x2000);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,11 +146,6 @@ class ConcreteMachine:
|
|||||||
public Activity::Source,
|
public Activity::Source,
|
||||||
public MSX::MemorySlotChangeHandler {
|
public MSX::MemorySlotChangeHandler {
|
||||||
private:
|
private:
|
||||||
static constexpr int RAMMemorySlot = 3;
|
|
||||||
static constexpr int RAMMemorySubSlot = 0;
|
|
||||||
|
|
||||||
static constexpr int ExtensionROMSubSlot = 1;
|
|
||||||
|
|
||||||
// Provide 512kb of memory for an MSX 2; 64kb for an MSX 1. 'Slightly' arbitrary.
|
// Provide 512kb of memory for an MSX 2; 64kb for an MSX 1. 'Slightly' arbitrary.
|
||||||
static constexpr size_t RAMSize = model == Target::Model::MSX2 ? 512 * 1024 : 64 * 1024;
|
static constexpr size_t RAMSize = model == Target::Model::MSX2 ? 512 * 1024 : 64 * 1024;
|
||||||
|
|
||||||
@ -253,7 +248,7 @@ class ConcreteMachine:
|
|||||||
const auto regional_bios = roms.find(regional_bios_name);
|
const auto regional_bios = roms.find(regional_bios_name);
|
||||||
if(regional_bios != roms.end()) {
|
if(regional_bios != roms.end()) {
|
||||||
regional_bios->second.resize(32768);
|
regional_bios->second.resize(32768);
|
||||||
memory_slots_[0].set_source(regional_bios->second);
|
bios_slot().set_source(regional_bios->second);
|
||||||
has_bios = true;
|
has_bios = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -270,40 +265,33 @@ class ConcreteMachine:
|
|||||||
);
|
);
|
||||||
bios[0x2c] = keyboard;
|
bios[0x2c] = keyboard;
|
||||||
|
|
||||||
memory_slots_[0].set_source(bios);
|
bios_slot().set_source(bios);
|
||||||
}
|
}
|
||||||
|
|
||||||
memory_slots_[0].map(0, 0, 0, 32768);
|
bios_slot().map(0, 0, 32768);
|
||||||
|
|
||||||
|
ram_slot().resize_source(RAMSize);
|
||||||
|
ram_slot().template map<MemorySlot::AccessType::ReadWrite>(0, 0, 65536);
|
||||||
|
|
||||||
if constexpr (model == Target::Model::MSX2) {
|
if constexpr (model == Target::Model::MSX2) {
|
||||||
// If there's an extension ROM, add it as a subslot in the same slot as RAM.
|
memory_slots_[3].supports_secondary_paging = true;
|
||||||
std::vector<uint8_t> ram_plus;
|
|
||||||
|
|
||||||
ram_plus.resize(RAMSize);
|
|
||||||
|
|
||||||
const auto extension = roms.find(ROM::Name::MSX2Extension);
|
const auto extension = roms.find(ROM::Name::MSX2Extension);
|
||||||
std::copy(extension->second.begin(), extension->second.end(), std::back_inserter(ram_plus));
|
extension->second.resize(32768);
|
||||||
|
extension_rom_slot().set_source(extension->second);
|
||||||
memory_slots_[RAMMemorySlot].supports_secondary_paging = true;
|
extension_rom_slot().map(0, 0, 32768);
|
||||||
memory_slots_[RAMMemorySlot].set_source(ram_plus);
|
|
||||||
|
|
||||||
memory_slots_[RAMMemorySlot].template map<MemorySlot::AccessType::ReadWrite>(RAMMemorySubSlot, 0, 0, 65536);
|
|
||||||
memory_slots_[RAMMemorySlot].map(ExtensionROMSubSlot, RAMSize, 0, 32768);
|
|
||||||
} else {
|
|
||||||
memory_slots_[RAMMemorySlot].resize_source(65536);
|
|
||||||
memory_slots_[RAMMemorySlot].template map<MemorySlot::AccessType::ReadWrite>(RAMMemorySubSlot, 0, 0, 65536);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a disk cartridge if any disks were supplied.
|
// Add a disk cartridge if any disks were supplied.
|
||||||
if(target.has_disk_drive) {
|
if(target.has_disk_drive) {
|
||||||
memory_slots_[2].handler = std::make_unique<DiskROM>(memory_slots_[2]);
|
disk_primary().handler = std::make_unique<DiskROM>(disk_slot());
|
||||||
|
|
||||||
std::vector<uint8_t> &dos = roms.find(ROM::Name::MSXDOS)->second;
|
std::vector<uint8_t> &dos = roms.find(ROM::Name::MSXDOS)->second;
|
||||||
dos.resize(16384);
|
dos.resize(16384);
|
||||||
memory_slots_[2].set_source(dos);
|
disk_slot().set_source(dos);
|
||||||
|
|
||||||
memory_slots_[2].map(0, 0, 0x4000, 0x2000);
|
disk_slot().map(0, 0x4000, 0x2000);
|
||||||
memory_slots_[2].unmap(0, 0x6000, 0x2000);
|
disk_slot().unmap(0x6000, 0x2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert the media.
|
// Insert the media.
|
||||||
@ -348,15 +336,15 @@ class ConcreteMachine:
|
|||||||
|
|
||||||
float get_confidence() final {
|
float get_confidence() final {
|
||||||
if(performed_unmapped_access_ || pc_zero_accesses_ > 1) return 0.0f;
|
if(performed_unmapped_access_ || pc_zero_accesses_ > 1) return 0.0f;
|
||||||
if(memory_slots_[1].handler) {
|
if(cartridge_primary().handler) {
|
||||||
return memory_slots_[1].handler->get_confidence();
|
return cartridge_primary().handler->get_confidence();
|
||||||
}
|
}
|
||||||
return 0.5f;
|
return 0.5f;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string debug_type() final {
|
std::string debug_type() final {
|
||||||
if(memory_slots_[1].handler) {
|
if(cartridge_primary().handler) {
|
||||||
return "MSX:" + memory_slots_[1].handler->debug_type();
|
return "MSX:" + cartridge_primary().handler->debug_type();
|
||||||
}
|
}
|
||||||
return "MSX";
|
return "MSX";
|
||||||
}
|
}
|
||||||
@ -364,26 +352,26 @@ class ConcreteMachine:
|
|||||||
bool insert_media(const Analyser::Static::Media &media) final {
|
bool insert_media(const Analyser::Static::Media &media) final {
|
||||||
if(!media.cartridges.empty()) {
|
if(!media.cartridges.empty()) {
|
||||||
const auto &segment = media.cartridges.front()->get_segments().front();
|
const auto &segment = media.cartridges.front()->get_segments().front();
|
||||||
auto &slot = memory_slots_[1];
|
auto &slot = cartridge_slot();
|
||||||
|
|
||||||
slot.set_source(segment.data);
|
slot.set_source(segment.data);
|
||||||
slot.map(0, 0, uint16_t(segment.start_address), std::min(segment.data.size(), 65536 - segment.start_address));
|
slot.map(0, uint16_t(segment.start_address), std::min(segment.data.size(), 65536 - segment.start_address));
|
||||||
|
|
||||||
auto msx_cartridge = dynamic_cast<Analyser::Static::MSX::Cartridge *>(media.cartridges.front().get());
|
auto msx_cartridge = dynamic_cast<Analyser::Static::MSX::Cartridge *>(media.cartridges.front().get());
|
||||||
if(msx_cartridge) {
|
if(msx_cartridge) {
|
||||||
switch(msx_cartridge->type) {
|
switch(msx_cartridge->type) {
|
||||||
default: break;
|
default: break;
|
||||||
case Analyser::Static::MSX::Cartridge::Konami:
|
case Analyser::Static::MSX::Cartridge::Konami:
|
||||||
slot.handler = std::make_unique<Cartridge::KonamiROMSlotHandler>(static_cast<MSX::MemorySlot &>(slot));
|
cartridge_primary().handler = std::make_unique<Cartridge::KonamiROMSlotHandler>(static_cast<MSX::MemorySlot &>(slot));
|
||||||
break;
|
break;
|
||||||
case Analyser::Static::MSX::Cartridge::KonamiWithSCC:
|
case Analyser::Static::MSX::Cartridge::KonamiWithSCC:
|
||||||
slot.handler = std::make_unique<Cartridge::KonamiWithSCCROMSlotHandler>(static_cast<MSX::MemorySlot &>(slot), scc_);
|
cartridge_primary().handler = std::make_unique<Cartridge::KonamiWithSCCROMSlotHandler>(static_cast<MSX::MemorySlot &>(slot), scc_);
|
||||||
break;
|
break;
|
||||||
case Analyser::Static::MSX::Cartridge::ASCII8kb:
|
case Analyser::Static::MSX::Cartridge::ASCII8kb:
|
||||||
slot.handler = std::make_unique<Cartridge::ASCII8kbROMSlotHandler>(static_cast<MSX::MemorySlot &>(slot));
|
cartridge_primary().handler = std::make_unique<Cartridge::ASCII8kbROMSlotHandler>(static_cast<MSX::MemorySlot &>(slot));
|
||||||
break;
|
break;
|
||||||
case Analyser::Static::MSX::Cartridge::ASCII16kb:
|
case Analyser::Static::MSX::Cartridge::ASCII16kb:
|
||||||
slot.handler = std::make_unique<Cartridge::ASCII16kbROMSlotHandler>(static_cast<MSX::MemorySlot &>(slot));
|
cartridge_primary().handler = std::make_unique<Cartridge::ASCII16kbROMSlotHandler>(static_cast<MSX::MemorySlot &>(slot));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -394,11 +382,11 @@ class ConcreteMachine:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!media.disks.empty()) {
|
if(!media.disks.empty()) {
|
||||||
DiskROM *disk_rom = get_disk_rom();
|
DiskROM *const handler = disk_handler();
|
||||||
if(disk_rom) {
|
if(handler) {
|
||||||
size_t drive = 0;
|
size_t drive = 0;
|
||||||
for(auto &disk : media.disks) {
|
for(auto &disk : media.disks) {
|
||||||
disk_rom->set_disk(disk, drive);
|
handler->set_disk(disk, drive);
|
||||||
drive++;
|
drive++;
|
||||||
if(drive == 2) break;
|
if(drive == 2) break;
|
||||||
}
|
}
|
||||||
@ -442,7 +430,7 @@ class ConcreteMachine:
|
|||||||
final_slot_ = &memory_slots_[primary >> 6];
|
final_slot_ = &memory_slots_[primary >> 6];
|
||||||
|
|
||||||
for(int c = 0; c < 8; c += 2) {
|
for(int c = 0; c < 8; c += 2) {
|
||||||
const MemorySlot &slot = memory_slots_[primary & 3];
|
const PrimarySlot &slot = memory_slots_[primary & 3];
|
||||||
primary >>= 2;
|
primary >>= 2;
|
||||||
|
|
||||||
read_pointers_[c] = slot.read_pointer(c);
|
read_pointers_[c] = slot.read_pointer(c);
|
||||||
@ -752,9 +740,9 @@ class ConcreteMachine:
|
|||||||
|
|
||||||
// MARK: - Activity::Source
|
// MARK: - Activity::Source
|
||||||
void set_activity_observer(Activity::Observer *observer) final {
|
void set_activity_observer(Activity::Observer *observer) final {
|
||||||
DiskROM *disk_rom = get_disk_rom();
|
DiskROM *handler = disk_handler();
|
||||||
if(disk_rom) {
|
if(handler) {
|
||||||
disk_rom->set_activity_observer(observer);
|
handler->set_activity_observer(observer);
|
||||||
}
|
}
|
||||||
i8255_port_handler_.set_activity_observer(observer);
|
i8255_port_handler_.set_activity_observer(observer);
|
||||||
}
|
}
|
||||||
@ -765,12 +753,6 @@ class ConcreteMachine:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t *ram() {
|
|
||||||
return memory_slots_[RAMMemorySlot].source().data();
|
|
||||||
}
|
|
||||||
DiskROM *get_disk_rom() {
|
|
||||||
return dynamic_cast<DiskROM *>(memory_slots_[2].handler.get());
|
|
||||||
}
|
|
||||||
void update_audio() {
|
void update_audio() {
|
||||||
speaker_.run_for(audio_queue_, time_since_ay_update_.divide_cycles(Cycles(2)));
|
speaker_.run_for(audio_queue_, time_since_ay_update_.divide_cycles(Cycles(2)));
|
||||||
}
|
}
|
||||||
@ -873,14 +855,15 @@ class ConcreteMachine:
|
|||||||
|
|
||||||
/// Optionally attaches non-default logic to any of the four things selectable
|
/// Optionally attaches non-default logic to any of the four things selectable
|
||||||
/// via the primary slot register.
|
/// via the primary slot register.
|
||||||
struct MemorySlot: public MSX::MemorySlot {
|
struct PrimarySlot: public MSX::PrimarySlot {
|
||||||
using MSX::MemorySlot::MemorySlot;
|
using MSX::PrimarySlot::PrimarySlot;
|
||||||
|
|
||||||
HalfCycles cycles_since_update;
|
HalfCycles cycles_since_update;
|
||||||
|
|
||||||
|
/// Storage for a slot-specialised handler.
|
||||||
std::unique_ptr<MemorySlotHandler> handler;
|
std::unique_ptr<MemorySlotHandler> handler;
|
||||||
};
|
};
|
||||||
MemorySlot memory_slots_[4];
|
PrimarySlot memory_slots_[4];
|
||||||
MemorySlot *final_slot_ = nullptr;
|
PrimarySlot *final_slot_ = nullptr;
|
||||||
|
|
||||||
HalfCycles time_since_ay_update_;
|
HalfCycles time_since_ay_update_;
|
||||||
|
|
||||||
@ -896,7 +879,40 @@ class ConcreteMachine:
|
|||||||
|
|
||||||
Ricoh::RP5C01::RP5C01 clock_;
|
Ricoh::RP5C01::RP5C01 clock_;
|
||||||
int next_clock_register_ = 0;
|
int next_clock_register_ = 0;
|
||||||
};
|
|
||||||
|
//
|
||||||
|
// Various helpers that dictate the slot arrangement used by this emulator.
|
||||||
|
//
|
||||||
|
MemorySlot &bios_slot() {
|
||||||
|
return memory_slots_[0].subslot(0);
|
||||||
|
}
|
||||||
|
MemorySlot &ram_slot() {
|
||||||
|
return memory_slots_[3].subslot(0);
|
||||||
|
}
|
||||||
|
MemorySlot &extension_rom_slot() {
|
||||||
|
return memory_slots_[3].subslot(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
MemorySlot &cartridge_slot() {
|
||||||
|
return cartridge_primary().subslot(0);
|
||||||
|
}
|
||||||
|
MemorySlot &disk_slot() {
|
||||||
|
return disk_primary().subslot(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
PrimarySlot &cartridge_primary() {
|
||||||
|
return memory_slots_[1];
|
||||||
|
}
|
||||||
|
PrimarySlot &disk_primary() {
|
||||||
|
return memory_slots_[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *ram() {
|
||||||
|
return ram_slot().source().data();
|
||||||
|
}
|
||||||
|
DiskROM *disk_handler() {
|
||||||
|
return dynamic_cast<DiskROM *>(disk_primary().handler.get());
|
||||||
|
}};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,31 +12,40 @@
|
|||||||
|
|
||||||
using namespace MSX;
|
using namespace MSX;
|
||||||
|
|
||||||
|
PrimarySlot::PrimarySlot(MemorySlotChangeHandler &handler) :
|
||||||
|
subslots_{handler, handler, handler, handler} {}
|
||||||
|
|
||||||
MemorySlot::MemorySlot(MemorySlotChangeHandler &handler) : handler_(handler) {
|
MemorySlot::MemorySlot(MemorySlotChangeHandler &handler) : handler_(handler) {
|
||||||
for(int subslot = 0; subslot < 4; subslot++) {
|
for(int region = 0; region < 8; region++) {
|
||||||
for(int region = 0; region < 8; region++) {
|
read_pointers_[region] = unmapped.data();
|
||||||
read_pointers_[subslot][region] = unmapped.data();
|
write_pointers_[region] = scratch.data();
|
||||||
write_pointers_[subslot][region] = scratch.data();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemorySlot::set_secondary_paging(uint8_t value) {
|
void PrimarySlot::set_secondary_paging(uint8_t value) {
|
||||||
secondary_paging_ = value;
|
secondary_paging_ = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t MemorySlot::secondary_paging() const {
|
uint8_t PrimarySlot::secondary_paging() const {
|
||||||
return secondary_paging_;
|
return secondary_paging_;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t *MemorySlot::read_pointer(int segment) const {
|
const uint8_t *PrimarySlot::read_pointer(int segment) const {
|
||||||
const int subslot = (secondary_paging_ >> (segment & ~1)) & 3;
|
const int subslot = (secondary_paging_ >> (segment & ~1)) & 3;
|
||||||
return read_pointers_[subslot][segment];
|
return subslots_[subslot].read_pointer(segment);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *PrimarySlot::write_pointer(int segment) const {
|
||||||
|
const int subslot = (secondary_paging_ >> (segment & ~1)) & 3;
|
||||||
|
return subslots_[subslot].write_pointer(segment);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t *MemorySlot::read_pointer(int segment) const {
|
||||||
|
return read_pointers_[segment];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *MemorySlot::write_pointer(int segment) const {
|
uint8_t *MemorySlot::write_pointer(int segment) const {
|
||||||
const int subslot = (secondary_paging_ >> (segment & ~1)) & 3;
|
return write_pointers_[segment];
|
||||||
return write_pointers_[subslot][segment];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemorySlot::set_source(const std::vector<uint8_t> &source) {
|
void MemorySlot::set_source(const std::vector<uint8_t> &source) {
|
||||||
@ -56,7 +65,7 @@ const std::vector<uint8_t> &MemorySlot::source() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <MSX::MemorySlot::AccessType type>
|
template <MSX::MemorySlot::AccessType type>
|
||||||
void MemorySlot::map(int subslot, std::size_t source_address, uint16_t destination_address, std::size_t length) {
|
void MemorySlot::map(std::size_t source_address, uint16_t destination_address, std::size_t length) {
|
||||||
assert(!(destination_address & 8191));
|
assert(!(destination_address & 8191));
|
||||||
assert(!(length & 8191));
|
assert(!(length & 8191));
|
||||||
assert(size_t(destination_address) + length <= 65536);
|
assert(size_t(destination_address) + length <= 65536);
|
||||||
@ -65,9 +74,9 @@ void MemorySlot::map(int subslot, std::size_t source_address, uint16_t destinati
|
|||||||
source_address %= source_.size();
|
source_address %= source_.size();
|
||||||
|
|
||||||
const int bank = int((destination_address >> 13) + c);
|
const int bank = int((destination_address >> 13) + c);
|
||||||
read_pointers_[subslot][bank] = &source_[source_address];
|
read_pointers_[bank] = &source_[source_address];
|
||||||
if constexpr (type == AccessType::ReadWrite) {
|
if constexpr (type == AccessType::ReadWrite) {
|
||||||
write_pointers_[subslot][bank] = read_pointers_[subslot][bank];
|
write_pointers_[bank] = read_pointers_[bank];
|
||||||
}
|
}
|
||||||
|
|
||||||
source_address += 8192;
|
source_address += 8192;
|
||||||
@ -76,17 +85,21 @@ void MemorySlot::map(int subslot, std::size_t source_address, uint16_t destinati
|
|||||||
handler_.did_page();
|
handler_.did_page();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemorySlot::unmap(int subslot, uint16_t destination_address, std::size_t length) {
|
void MemorySlot::unmap(uint16_t destination_address, std::size_t length) {
|
||||||
assert(!(destination_address & 8191));
|
assert(!(destination_address & 8191));
|
||||||
assert(!(length & 8191));
|
assert(!(length & 8191));
|
||||||
assert(size_t(destination_address) + length <= 65536);
|
assert(size_t(destination_address) + length <= 65536);
|
||||||
|
|
||||||
for(std::size_t c = 0; c < (length >> 13); ++c) {
|
for(std::size_t c = 0; c < (length >> 13); ++c) {
|
||||||
read_pointers_[subslot][(destination_address >> 13) + c] = nullptr;
|
read_pointers_[(destination_address >> 13) + c] = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
handler_.did_page();
|
handler_.did_page();
|
||||||
}
|
}
|
||||||
|
|
||||||
template void MemorySlot::map<MSX::MemorySlot::AccessType::Read>(int subslot, std::size_t source_address, uint16_t destination_address, std::size_t length);
|
MemorySlot &PrimarySlot::subslot(int slot) {
|
||||||
template void MemorySlot::map<MSX::MemorySlot::AccessType::ReadWrite>(int subslot, std::size_t source_address, uint16_t destination_address, std::size_t length);
|
return subslots_[slot];
|
||||||
|
}
|
||||||
|
|
||||||
|
template void MemorySlot::map<MSX::MemorySlot::AccessType::Read>(std::size_t source_address, uint16_t destination_address, std::size_t length);
|
||||||
|
template void MemorySlot::map<MSX::MemorySlot::AccessType::ReadWrite>(std::size_t source_address, uint16_t destination_address, std::size_t length);
|
||||||
|
@ -38,15 +38,6 @@ class MemorySlot {
|
|||||||
public:
|
public:
|
||||||
MemorySlot(MemorySlotChangeHandler &);
|
MemorySlot(MemorySlotChangeHandler &);
|
||||||
|
|
||||||
/// Attempts to write the argument as the secondary paging selection.
|
|
||||||
void set_secondary_paging(uint8_t);
|
|
||||||
|
|
||||||
/// @returns The value most recently provided to @c set_secondary_paging.
|
|
||||||
uint8_t secondary_paging() const;
|
|
||||||
|
|
||||||
/// Indicates whether this slot supports secondary paging.
|
|
||||||
bool supports_secondary_paging = false;
|
|
||||||
|
|
||||||
/// @returns A pointer to the area of memory currently underneath @c address that
|
/// @returns A pointer to the area of memory currently underneath @c address that
|
||||||
/// should be read
|
/// should be read
|
||||||
const uint8_t *read_pointer(int segment) const;
|
const uint8_t *read_pointer(int segment) const;
|
||||||
@ -73,7 +64,6 @@ class MemorySlot {
|
|||||||
/// supplied to @c set_source to the region indicated by
|
/// supplied to @c set_source to the region indicated by
|
||||||
/// @c destination_address and @c length within @c subslot.
|
/// @c destination_address and @c length within @c subslot.
|
||||||
template <AccessType type = AccessType::Read> void map(
|
template <AccessType type = AccessType::Read> void map(
|
||||||
int subslot,
|
|
||||||
std::size_t source_address,
|
std::size_t source_address,
|
||||||
uint16_t destination_address,
|
uint16_t destination_address,
|
||||||
std::size_t length);
|
std::size_t length);
|
||||||
@ -83,15 +73,13 @@ class MemorySlot {
|
|||||||
/// will be used to field accesses to that area, allowing for areas that are not
|
/// will be used to field accesses to that area, allowing for areas that are not
|
||||||
/// backed by memory to be modelled.
|
/// backed by memory to be modelled.
|
||||||
void unmap(
|
void unmap(
|
||||||
int subslot,
|
|
||||||
uint16_t destination_address,
|
uint16_t destination_address,
|
||||||
std::size_t length);
|
std::size_t length);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<uint8_t> source_;
|
std::vector<uint8_t> source_;
|
||||||
uint8_t *read_pointers_[4][8];
|
uint8_t *read_pointers_[8];
|
||||||
uint8_t *write_pointers_[4][8];
|
uint8_t *write_pointers_[8];
|
||||||
uint8_t secondary_paging_ = 0;
|
|
||||||
|
|
||||||
MemorySlotChangeHandler &handler_;
|
MemorySlotChangeHandler &handler_;
|
||||||
|
|
||||||
@ -100,6 +88,34 @@ class MemorySlot {
|
|||||||
inline static MemoryChunk scratch;
|
inline static MemoryChunk scratch;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PrimarySlot {
|
||||||
|
public:
|
||||||
|
PrimarySlot(MemorySlotChangeHandler &);
|
||||||
|
|
||||||
|
/// @returns A pointer to the area of memory currently underneath @c address that
|
||||||
|
/// should be read
|
||||||
|
const uint8_t *read_pointer(int segment) const;
|
||||||
|
|
||||||
|
/// @returns A pointer to the area of memory currently underneath @c address.
|
||||||
|
uint8_t *write_pointer(int segment) const;
|
||||||
|
|
||||||
|
/// Attempts to write the argument as the secondary paging selection.
|
||||||
|
void set_secondary_paging(uint8_t);
|
||||||
|
|
||||||
|
/// @returns The value most recently provided to @c set_secondary_paging.
|
||||||
|
uint8_t secondary_paging() const;
|
||||||
|
|
||||||
|
/// Indicates whether this slot supports secondary paging.
|
||||||
|
bool supports_secondary_paging = false;
|
||||||
|
|
||||||
|
/// Provides the subslot at the specified index.
|
||||||
|
MemorySlot &subslot(int);
|
||||||
|
|
||||||
|
private:
|
||||||
|
MemorySlot subslots_[4];
|
||||||
|
uint8_t secondary_paging_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class MemorySlotHandler {
|
class MemorySlotHandler {
|
||||||
public:
|
public:
|
||||||
virtual ~MemorySlotHandler() {}
|
virtual ~MemorySlotHandler() {}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user