mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-25 02:29:08 +00:00
The MSX analyser is now smart enough not to be definitive when it's uncertain.
The cartridge type has also migrated to being a property of the cartridge, prefiguring my intention to discard the static analyser union.
This commit is contained in:
parent
f2519f4fd7
commit
e025674eb2
40
Analyser/Static/MSX/Cartridge.hpp
Normal file
40
Analyser/Static/MSX/Cartridge.hpp
Normal file
@ -0,0 +1,40 @@
|
||||
//
|
||||
// Cartridge.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 25/01/2018.
|
||||
// Copyright © 2018 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef Cartridge_hpp
|
||||
#define Cartridge_hpp
|
||||
|
||||
#include "../../../Storage/Cartridge/Cartridge.hpp"
|
||||
|
||||
namespace Analyser {
|
||||
namespace Static {
|
||||
namespace MSX {
|
||||
|
||||
/*!
|
||||
Extends the base cartridge class by adding a (guess at) the banking scheme.
|
||||
*/
|
||||
struct Cartridge: public ::Storage::Cartridge::Cartridge {
|
||||
enum Type {
|
||||
None,
|
||||
Konami,
|
||||
KonamiWithSCC,
|
||||
ASCII8kb,
|
||||
ASCII16kb,
|
||||
FMPac
|
||||
};
|
||||
const Type type;
|
||||
|
||||
Cartridge(const std::vector<Segment> &segments, Type type) :
|
||||
Storage::Cartridge::Cartridge(segments), type(type) {}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Cartridge_hpp */
|
@ -8,12 +8,43 @@
|
||||
|
||||
#include "StaticAnalyser.hpp"
|
||||
|
||||
#include "Cartridge.hpp"
|
||||
#include "Tape.hpp"
|
||||
#include "../Disassembler/Z80.hpp"
|
||||
#include "../Disassembler/AddressMapper.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
static std::unique_ptr<Analyser::Static::Target> CartridgeTarget(
|
||||
const Storage::Cartridge::Cartridge::Segment &segment,
|
||||
uint16_t start_address,
|
||||
Analyser::Static::MSX::Cartridge::Type type,
|
||||
float confidence) {
|
||||
|
||||
// Size down to a multiple of 8kb in size and apply the start address.
|
||||
std::vector<Storage::Cartridge::Cartridge::Segment> output_segments;
|
||||
if(segment.data.size() & 0x1fff) {
|
||||
std::vector<uint8_t> truncated_data;
|
||||
std::vector<uint8_t>::difference_type truncated_size = static_cast<std::vector<uint8_t>::difference_type>(segment.data.size()) & ~0x1fff;
|
||||
truncated_data.insert(truncated_data.begin(), segment.data.begin(), segment.data.begin() + truncated_size);
|
||||
output_segments.emplace_back(start_address, truncated_data);
|
||||
} else {
|
||||
output_segments.emplace_back(start_address, segment.data);
|
||||
}
|
||||
|
||||
std::unique_ptr<Analyser::Static::Target> target(new Analyser::Static::Target);
|
||||
target->machine = Analyser::Machine::MSX;
|
||||
target->confidence = confidence;
|
||||
|
||||
if(type == Analyser::Static::MSX::Cartridge::Type::None) {
|
||||
target->media.cartridges.emplace_back(new Storage::Cartridge::Cartridge(output_segments));
|
||||
} else {
|
||||
target->media.cartridges.emplace_back(new Analyser::Static::MSX::Cartridge(output_segments, type));
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/*
|
||||
Expected standard cartridge format:
|
||||
|
||||
@ -23,11 +54,21 @@
|
||||
DEFW device; pointer to expansion device handler, 0 if no such handler
|
||||
DEFW basic ; pointer to the start of a tokenized basicprogram, 0 if no basicprogram
|
||||
DEFS 6,0 ; room reserved for future extensions
|
||||
*/
|
||||
static std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>>
|
||||
MSXCartridgesFrom(const std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges, Analyser::Static::Target &target) {
|
||||
std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>> msx_cartridges;
|
||||
|
||||
MSX cartridges often include banking hardware; those games were marketed as MegaROMs. The file
|
||||
format that the MSX community has decided upon doesn't retain the type of hardware included, so
|
||||
this analyser has to guess.
|
||||
|
||||
(additional audio hardware is also sometimes included, but it's implied by the banking hardware)
|
||||
*/
|
||||
static std::vector<std::unique_ptr<Analyser::Static::Target>> CartridgeTargetsFrom(
|
||||
const std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges) {
|
||||
// No cartridges implies no targets.
|
||||
if(cartridges.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Analyser::Static::Target>> targets;
|
||||
for(const auto &cartridge : cartridges) {
|
||||
const auto &segments = cartridge->get_segments();
|
||||
|
||||
@ -57,154 +98,174 @@ static std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>>
|
||||
uint16_t init_address = static_cast<uint16_t>(segment.data[2] | (segment.data[3] << 8));
|
||||
// TODO: check for a rational init address?
|
||||
|
||||
// If this ROM is less than 48kb in size then it's an ordinary ROM. Just emplace it and move on.
|
||||
if(data_size <= 0xc000) {
|
||||
targets.emplace_back(CartridgeTarget(segment, start_address, Analyser::Static::MSX::Cartridge::Type::None, 1.0));
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this ROM is greater than 48kb in size then some sort of MegaROM scheme must
|
||||
// be at play; disassemble to try to figure it out.
|
||||
target.msx.cartridge_type = Analyser::Static::MSXCartridgeType::None;
|
||||
if(data_size > 0xc000) {
|
||||
std::vector<uint8_t> first_16k;
|
||||
first_16k.insert(first_16k.begin(), segment.data.begin(), segment.data.begin() + 8192);
|
||||
Analyser::Static::Z80::Disassembly disassembly =
|
||||
Analyser::Static::Z80::Disassemble(
|
||||
first_16k,
|
||||
Analyser::Static::Disassembler::OffsetMapper(start_address),
|
||||
{ init_address }
|
||||
);
|
||||
std::vector<uint8_t> first_8k;
|
||||
first_8k.insert(first_8k.begin(), segment.data.begin(), segment.data.begin() + 8192);
|
||||
Analyser::Static::Z80::Disassembly disassembly =
|
||||
Analyser::Static::Z80::Disassemble(
|
||||
first_8k,
|
||||
Analyser::Static::Disassembler::OffsetMapper(start_address),
|
||||
{ init_address }
|
||||
);
|
||||
|
||||
// Look for a indirect store followed by an unconditional JP or CALL into another
|
||||
// segment, that's a fairly explicit sign where found.
|
||||
using Instruction = Analyser::Static::Z80::Instruction;
|
||||
std::map<uint16_t, Instruction> &instructions = disassembly.instructions_by_address;
|
||||
bool is_ascii = false;
|
||||
auto iterator = instructions.begin();
|
||||
while(iterator != instructions.end()) {
|
||||
auto next_iterator = iterator;
|
||||
next_iterator++;
|
||||
if(next_iterator == instructions.end()) break;
|
||||
// // Look for a indirect store followed by an unconditional JP or CALL into another
|
||||
// // segment, that's a fairly explicit sign where found.
|
||||
using Instruction = Analyser::Static::Z80::Instruction;
|
||||
std::map<uint16_t, Instruction> &instructions = disassembly.instructions_by_address;
|
||||
bool is_ascii = false;
|
||||
// auto iterator = instructions.begin();
|
||||
// while(iterator != instructions.end()) {
|
||||
// auto next_iterator = iterator;
|
||||
// next_iterator++;
|
||||
// if(next_iterator == instructions.end()) break;
|
||||
//
|
||||
// if( iterator->second.operation == Instruction::Operation::LD &&
|
||||
// iterator->second.destination == Instruction::Location::Operand_Indirect &&
|
||||
// (
|
||||
// iterator->second.operand == 0x5000 ||
|
||||
// iterator->second.operand == 0x6000 ||
|
||||
// iterator->second.operand == 0x6800 ||
|
||||
// iterator->second.operand == 0x7000 ||
|
||||
// iterator->second.operand == 0x77ff ||
|
||||
// iterator->second.operand == 0x7800 ||
|
||||
// iterator->second.operand == 0x8000 ||
|
||||
// iterator->second.operand == 0x9000 ||
|
||||
// iterator->second.operand == 0xa000
|
||||
// ) &&
|
||||
// (
|
||||
// next_iterator->second.operation == Instruction::Operation::CALL ||
|
||||
// next_iterator->second.operation == Instruction::Operation::JP
|
||||
// ) &&
|
||||
// ((next_iterator->second.operand >> 13) != (0x4000 >> 13))
|
||||
// ) {
|
||||
// const uint16_t address = static_cast<uint16_t>(next_iterator->second.operand);
|
||||
// switch(iterator->second.operand) {
|
||||
// case 0x6000:
|
||||
// if(address >= 0x6000 && address < 0x8000) {
|
||||
// target.msx.cartridge_type = Analyser::Static::MSXCartridgeType::KonamiWithSCC;
|
||||
// }
|
||||
// break;
|
||||
// case 0x6800:
|
||||
// if(address >= 0x6000 && address < 0x6800) {
|
||||
// target.msx.cartridge_type = Analyser::Static::MSXCartridgeType::ASCII8kb;
|
||||
// }
|
||||
// break;
|
||||
// case 0x7000:
|
||||
// if(address >= 0x6000 && address < 0x8000) {
|
||||
// target.msx.cartridge_type = Analyser::Static::MSXCartridgeType::KonamiWithSCC;
|
||||
// }
|
||||
// if(address >= 0x7000 && address < 0x7800) {
|
||||
// is_ascii = true;
|
||||
// }
|
||||
// break;
|
||||
// case 0x77ff:
|
||||
// if(address >= 0x7000 && address < 0x7800) {
|
||||
// target.msx.cartridge_type = Analyser::Static::MSXCartridgeType::ASCII16kb;
|
||||
// }
|
||||
// break;
|
||||
// case 0x7800:
|
||||
// if(address >= 0xa000 && address < 0xc000) {
|
||||
// target.msx.cartridge_type = Analyser::Static::MSXCartridgeType::ASCII8kb;
|
||||
// }
|
||||
// break;
|
||||
// case 0x8000:
|
||||
// if(address >= 0x8000 && address < 0xa000) {
|
||||
// target.msx.cartridge_type = Analyser::Static::MSXCartridgeType::KonamiWithSCC;
|
||||
// }
|
||||
// break;
|
||||
// case 0x9000:
|
||||
// if(address >= 0x8000 && address < 0xa000) {
|
||||
// target.msx.cartridge_type = Analyser::Static::MSXCartridgeType::KonamiWithSCC;
|
||||
// }
|
||||
// break;
|
||||
// case 0xa000:
|
||||
// if(address >= 0xa000 && address < 0xc000) {
|
||||
// target.msx.cartridge_type = Analyser::Static::MSXCartridgeType::Konami;
|
||||
// }
|
||||
// break;
|
||||
// case 0xb000:
|
||||
// if(address >= 0xa000 && address < 0xc000) {
|
||||
// target.msx.cartridge_type = Analyser::Static::MSXCartridgeType::KonamiWithSCC;
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// iterator = next_iterator;
|
||||
|
||||
if( iterator->second.operation == Instruction::Operation::LD &&
|
||||
iterator->second.destination == Instruction::Location::Operand_Indirect &&
|
||||
(
|
||||
iterator->second.operand == 0x5000 ||
|
||||
iterator->second.operand == 0x6000 ||
|
||||
iterator->second.operand == 0x6800 ||
|
||||
iterator->second.operand == 0x7000 ||
|
||||
iterator->second.operand == 0x77ff ||
|
||||
iterator->second.operand == 0x7800 ||
|
||||
iterator->second.operand == 0x8000 ||
|
||||
iterator->second.operand == 0x9000 ||
|
||||
iterator->second.operand == 0xa000
|
||||
) &&
|
||||
(
|
||||
next_iterator->second.operation == Instruction::Operation::CALL ||
|
||||
next_iterator->second.operation == Instruction::Operation::JP
|
||||
) &&
|
||||
((next_iterator->second.operand >> 13) != (0x4000 >> 13))
|
||||
) {
|
||||
const uint16_t address = static_cast<uint16_t>(next_iterator->second.operand);
|
||||
switch(iterator->second.operand) {
|
||||
case 0x6000:
|
||||
if(address >= 0x6000 && address < 0x8000) {
|
||||
target.msx.cartridge_type = Analyser::Static::MSXCartridgeType::KonamiWithSCC;
|
||||
}
|
||||
break;
|
||||
case 0x6800:
|
||||
if(address >= 0x6000 && address < 0x6800) {
|
||||
target.msx.cartridge_type = Analyser::Static::MSXCartridgeType::ASCII8kb;
|
||||
}
|
||||
break;
|
||||
case 0x7000:
|
||||
if(address >= 0x6000 && address < 0x8000) {
|
||||
target.msx.cartridge_type = Analyser::Static::MSXCartridgeType::KonamiWithSCC;
|
||||
}
|
||||
if(address >= 0x7000 && address < 0x7800) {
|
||||
is_ascii = true;
|
||||
}
|
||||
break;
|
||||
case 0x77ff:
|
||||
if(address >= 0x7000 && address < 0x7800) {
|
||||
target.msx.cartridge_type = Analyser::Static::MSXCartridgeType::ASCII16kb;
|
||||
}
|
||||
break;
|
||||
case 0x7800:
|
||||
if(address >= 0xa000 && address < 0xc000) {
|
||||
target.msx.cartridge_type = Analyser::Static::MSXCartridgeType::ASCII8kb;
|
||||
}
|
||||
break;
|
||||
case 0x8000:
|
||||
if(address >= 0x8000 && address < 0xa000) {
|
||||
target.msx.cartridge_type = Analyser::Static::MSXCartridgeType::KonamiWithSCC;
|
||||
}
|
||||
break;
|
||||
case 0x9000:
|
||||
if(address >= 0x8000 && address < 0xa000) {
|
||||
target.msx.cartridge_type = Analyser::Static::MSXCartridgeType::KonamiWithSCC;
|
||||
}
|
||||
break;
|
||||
case 0xa000:
|
||||
if(address >= 0xa000 && address < 0xc000) {
|
||||
target.msx.cartridge_type = Analyser::Static::MSXCartridgeType::Konami;
|
||||
}
|
||||
break;
|
||||
case 0xb000:
|
||||
if(address >= 0xa000 && address < 0xc000) {
|
||||
target.msx.cartridge_type = Analyser::Static::MSXCartridgeType::KonamiWithSCC;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iterator = next_iterator;
|
||||
}
|
||||
|
||||
if(target.msx.cartridge_type == Analyser::Static::MSXCartridgeType::None) {
|
||||
// Look for LD (nnnn), A instructions, and collate those addresses.
|
||||
std::map<uint16_t, int> address_counts;
|
||||
for(const auto &instruction_pair : instructions) {
|
||||
if( instruction_pair.second.operation == Instruction::Operation::LD &&
|
||||
instruction_pair.second.destination == Instruction::Location::Operand_Indirect &&
|
||||
instruction_pair.second.source == Instruction::Location::A) {
|
||||
address_counts[static_cast<uint16_t>(instruction_pair.second.operand)]++;
|
||||
}
|
||||
}
|
||||
|
||||
// Sort possible cartridge types.
|
||||
using Possibility = std::pair<Analyser::Static::MSXCartridgeType, int>;
|
||||
std::vector<Possibility> possibilities;
|
||||
// Add to list in order of declining probability, so that stable_sort below prefers
|
||||
// the more likely option in a tie.
|
||||
possibilities.push_back(std::make_pair(Analyser::Static::MSXCartridgeType::ASCII8kb, address_counts[0x6000] + address_counts[0x6800] + address_counts[0x7000] + address_counts[0x7800]));
|
||||
possibilities.push_back(std::make_pair(Analyser::Static::MSXCartridgeType::ASCII16kb, address_counts[0x6000] + address_counts[0x7000] + address_counts[0x77ff]));
|
||||
if(!is_ascii) possibilities.push_back(std::make_pair(Analyser::Static::MSXCartridgeType::Konami, address_counts[0x6000] + address_counts[0x8000] + address_counts[0xa000]));
|
||||
if(!is_ascii) possibilities.push_back(std::make_pair(Analyser::Static::MSXCartridgeType::KonamiWithSCC, address_counts[0x5000] + address_counts[0x7000] + address_counts[0x9000] + address_counts[0xb000]));
|
||||
std::stable_sort(possibilities.begin(), possibilities.end(), [](const Possibility &a, const Possibility &b) {
|
||||
return a.second > b.second;
|
||||
});
|
||||
|
||||
target.msx.cartridge_type = possibilities[0].first;
|
||||
// Look for LD (nnnn), A instructions, and collate those addresses.
|
||||
std::map<uint16_t, int> address_counts;
|
||||
for(const auto &instruction_pair : instructions) {
|
||||
if( instruction_pair.second.operation == Instruction::Operation::LD &&
|
||||
instruction_pair.second.destination == Instruction::Location::Operand_Indirect &&
|
||||
instruction_pair.second.source == Instruction::Location::A) {
|
||||
address_counts[static_cast<uint16_t>(instruction_pair.second.operand)]++;
|
||||
}
|
||||
}
|
||||
|
||||
// Size down to a multiple of 8kb in size and apply the start address.
|
||||
std::vector<Storage::Cartridge::Cartridge::Segment> output_segments;
|
||||
if(segment.data.size() & 0x1fff) {
|
||||
std::vector<uint8_t> truncated_data;
|
||||
std::vector<uint8_t>::difference_type truncated_size = static_cast<std::vector<uint8_t>::difference_type>(segment.data.size()) & ~0x1fff;
|
||||
truncated_data.insert(truncated_data.begin(), segment.data.begin(), segment.data.begin() + truncated_size);
|
||||
output_segments.emplace_back(start_address, truncated_data);
|
||||
} else {
|
||||
output_segments.emplace_back(start_address, segment.data);
|
||||
// Weight confidences by number of observed hits.
|
||||
float total_hits =
|
||||
static_cast<float>(
|
||||
address_counts[0x6000] + address_counts[0x6800] +
|
||||
address_counts[0x7000] + address_counts[0x7800] +
|
||||
address_counts[0x77ff] + address_counts[0x8000] +
|
||||
address_counts[0xa000] + address_counts[0x5000] +
|
||||
address_counts[0x9000] + address_counts[0xb000]
|
||||
);
|
||||
|
||||
targets.push_back(CartridgeTarget(
|
||||
segment,
|
||||
start_address,
|
||||
Analyser::Static::MSX::Cartridge::ASCII8kb,
|
||||
static_cast<float>( address_counts[0x6000] +
|
||||
address_counts[0x6800] +
|
||||
address_counts[0x7000] +
|
||||
address_counts[0x7800]) / total_hits));
|
||||
targets.push_back(CartridgeTarget(
|
||||
segment,
|
||||
start_address,
|
||||
Analyser::Static::MSX::Cartridge::ASCII16kb,
|
||||
static_cast<float>( address_counts[0x6000] +
|
||||
address_counts[0x7000] +
|
||||
address_counts[0x77ff]) / total_hits));
|
||||
if(!is_ascii) {
|
||||
targets.push_back(CartridgeTarget(
|
||||
segment,
|
||||
start_address,
|
||||
Analyser::Static::MSX::Cartridge::Konami,
|
||||
static_cast<float>( address_counts[0x6000] +
|
||||
address_counts[0x8000] +
|
||||
address_counts[0xa000]) / total_hits));
|
||||
}
|
||||
if(!is_ascii) {
|
||||
targets.push_back(CartridgeTarget(
|
||||
segment,
|
||||
start_address,
|
||||
Analyser::Static::MSX::Cartridge::KonamiWithSCC,
|
||||
static_cast<float>( address_counts[0x5000] +
|
||||
address_counts[0x7000] +
|
||||
address_counts[0x9000] +
|
||||
address_counts[0xb000]) / total_hits));
|
||||
}
|
||||
msx_cartridges.emplace_back(new Storage::Cartridge::Cartridge(output_segments));
|
||||
}
|
||||
|
||||
return msx_cartridges;
|
||||
return targets;
|
||||
}
|
||||
|
||||
void Analyser::Static::MSX::AddTargets(const Media &media, std::vector<std::unique_ptr<Target>> &destination) {
|
||||
std::unique_ptr<Target> target(new Target);
|
||||
// Append targets for any cartridges that look correct.
|
||||
std::vector<std::unique_ptr<Target>> cartridge_targets = CartridgeTargetsFrom(media.cartridges);
|
||||
std::move(cartridge_targets.begin(), cartridge_targets.end(), std::back_inserter(destination));
|
||||
|
||||
// Obtain only those cartridges which it looks like an MSX would understand.
|
||||
target->media.cartridges = MSXCartridgesFrom(media.cartridges, *target);
|
||||
// Consider building a target for disks and/or tapes.
|
||||
std::unique_ptr<Target> target(new Target);
|
||||
|
||||
// Check tapes for loadable files.
|
||||
for(const auto &tape : media.tapes) {
|
||||
|
@ -164,5 +164,11 @@ std::vector<std::unique_ptr<Target>> Analyser::Static::GetTargets(const char *fi
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by initial confidence. Use a stable sort in case any of the machine-specific analysers
|
||||
// picked their insertion order carefully.
|
||||
std::stable_sort(targets.begin(), targets.end(), [](auto &a, auto &b) {
|
||||
return a->confidence > b->confidence;
|
||||
});
|
||||
|
||||
return targets;
|
||||
}
|
||||
|
@ -42,15 +42,6 @@ enum class Atari2600PagingModel {
|
||||
Pitfall2
|
||||
};
|
||||
|
||||
enum class MSXCartridgeType {
|
||||
None,
|
||||
Konami,
|
||||
KonamiWithSCC,
|
||||
ASCII8kb,
|
||||
ASCII16kb,
|
||||
FMPac
|
||||
};
|
||||
|
||||
enum class ZX8081MemoryModel {
|
||||
Unexpanded,
|
||||
SixteenKB,
|
||||
@ -119,10 +110,6 @@ struct Target {
|
||||
struct {
|
||||
AmstradCPCModel model;
|
||||
} amstradcpc;
|
||||
|
||||
struct {
|
||||
MSXCartridgeType cartridge_type;
|
||||
} msx;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "Keyboard.hpp"
|
||||
#include "ROMSlotHandler.hpp"
|
||||
|
||||
#include "../../Analyser/Static/MSX/Cartridge.hpp"
|
||||
#include "Cartridges/ASCII8kb.hpp"
|
||||
#include "Cartridges/ASCII16kb.hpp"
|
||||
#include "Cartridges/Konami.hpp"
|
||||
@ -175,23 +176,6 @@ class ConcreteMachine:
|
||||
if(target.loading_command.length()) {
|
||||
type_string(target.loading_command);
|
||||
}
|
||||
|
||||
// Attach the hardware necessary for a game cartridge, if any.
|
||||
switch(target.msx.cartridge_type) {
|
||||
default: break;
|
||||
case Analyser::Static::MSXCartridgeType::Konami:
|
||||
memory_slots_[1].set_handler(new Cartridge::KonamiROMSlotHandler(*this, 1));
|
||||
break;
|
||||
case Analyser::Static::MSXCartridgeType::KonamiWithSCC:
|
||||
memory_slots_[1].set_handler(new Cartridge::KonamiWithSCCROMSlotHandler(*this, 1, scc_));
|
||||
break;
|
||||
case Analyser::Static::MSXCartridgeType::ASCII8kb:
|
||||
memory_slots_[1].set_handler(new Cartridge::ASCII8kbROMSlotHandler(*this, 1));
|
||||
break;
|
||||
case Analyser::Static::MSXCartridgeType::ASCII16kb:
|
||||
memory_slots_[1].set_handler(new Cartridge::ASCII16kbROMSlotHandler(*this, 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool insert_media(const Analyser::Static::Media &media) override {
|
||||
@ -199,6 +183,25 @@ class ConcreteMachine:
|
||||
const auto &segment = media.cartridges.front()->get_segments().front();
|
||||
memory_slots_[1].source = segment.data;
|
||||
map(1, 0, static_cast<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());
|
||||
if(msx_cartridge) {
|
||||
switch(msx_cartridge->type) {
|
||||
default: break;
|
||||
case Analyser::Static::MSX::Cartridge::Konami:
|
||||
memory_slots_[1].set_handler(new Cartridge::KonamiROMSlotHandler(*this, 1));
|
||||
break;
|
||||
case Analyser::Static::MSX::Cartridge::KonamiWithSCC:
|
||||
memory_slots_[1].set_handler(new Cartridge::KonamiWithSCCROMSlotHandler(*this, 1, scc_));
|
||||
break;
|
||||
case Analyser::Static::MSX::Cartridge::ASCII8kb:
|
||||
memory_slots_[1].set_handler(new Cartridge::ASCII8kbROMSlotHandler(*this, 1));
|
||||
break;
|
||||
case Analyser::Static::MSX::Cartridge::ASCII16kb:
|
||||
memory_slots_[1].set_handler(new Cartridge::ASCII16kbROMSlotHandler(*this, 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!media.tapes.empty()) {
|
||||
|
@ -644,6 +644,7 @@
|
||||
/* Begin PBXFileReference section */
|
||||
4B01A6871F22F0DB001FD6E3 /* Z80MemptrTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Z80MemptrTests.swift; sourceTree = "<group>"; };
|
||||
4B046DC31CFE651500E9E45E /* CRTMachine.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CRTMachine.hpp; sourceTree = "<group>"; };
|
||||
4B047075201ABC180047AB0D /* Cartridge.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Cartridge.hpp; sourceTree = "<group>"; };
|
||||
4B049CDC1DA3C82F00322067 /* BCDTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BCDTest.swift; sourceTree = "<group>"; };
|
||||
4B055A6A1FAE763F0060FFFF /* Clock Signal Kiosk */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "Clock Signal Kiosk"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
4B055A771FAE78210060FFFF /* SDL2.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL2.framework; path = ../../../../Library/Frameworks/SDL2.framework; sourceTree = SOURCE_ROOT; };
|
||||
@ -2163,6 +2164,7 @@
|
||||
children = (
|
||||
4B894513201967B4007DE474 /* StaticAnalyser.cpp */,
|
||||
4B894512201967B4007DE474 /* Tape.cpp */,
|
||||
4B047075201ABC180047AB0D /* Cartridge.hpp */,
|
||||
4B894510201967B4007DE474 /* StaticAnalyser.hpp */,
|
||||
4B894511201967B4007DE474 /* Tape.hpp */,
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user