29 auto result = std::make_unique<HardwareConfig>(
30 motherBoard, std::move(machineName));
32 result->load(
"machines");
37 MSXMotherBoard& motherBoard, std::string extensionName, std::string_view slotName)
39 auto result = std::make_unique<HardwareConfig>(
40 motherBoard, std::move(extensionName));
41 result->load(
"extensions");
42 result->setName(result->hwName);
44 result->setSlot(slotName);
50 std::string_view slotName, std::span<const TclObject> options)
52 auto result = std::make_unique<HardwareConfig>(motherBoard,
"rom");
53 result->setName(romFile);
56 std::vector<std::string_view> ipsFiles;
65 throw MSXException(
"Invalid option \"", args.front().getString(),
'\"');
70 for (
const auto& ips : ipsFiles) {
79 throw MSXException(
"Invalid ROM file: ", resolvedFilename);
108 auto* devices = extension->setFirstChild(doc.
allocateElement(
"devices"));
109 auto* primary = devices->setFirstChild(doc.
allocateElement(
"primary"));
112 auto* secondary = primary->setFirstChild(doc.
allocateElement(
"secondary"));
121 auto* mapperType = sound->setNextSibling(doc.
allocateElement(
"mappertype"));
122 mapperType->setData(mapper.empty() ?
"auto" : doc.
allocateString(mapper));
123 auto* sramName = mapperType->setNextSibling(doc.
allocateElement(
"sramname"));
126 auto* rfName = rom->setFirstChild(doc.
allocateElement(
"resolvedFilename"));
130 if (!ipsFiles.empty()) {
137 result->setConfig(extension);
138 result->setFileContext(std::move(context));
145 assert(type ==
Type::ROM &&
"should only be used on ROM extensions");
147 const auto* p = d->findChild(
"primary"); assert(p);
148 const auto* s = p->findChild(
"secondary"); assert(s);
149 const auto*
R = s->findChild(
"ROM"); assert(
R);
150 const auto* r =
R->findChild(
"rom"); assert(r);
151 const auto* f = r->findChild(
"filename"); assert(f);
156 : motherBoard(motherBoard_)
157 , hwName(
std::move(hwName_))
159 for (
auto& sub : externalSlots) {
175 std::cerr << e.getMessage() <<
'\n';
179 while (!devices.empty()) {
184 for (
auto ps :
xrange(4)) {
185 for (
auto ss :
xrange(4)) {
186 if (externalSlots[ps][ss]) {
190 if (externalPrimSlots[ps]) {
191 slotManager.removeExternalSlot(ps);
193 if (expandedSlots[ps]) {
196 if (allocatedPrimarySlots[ps]) {
197 slotManager.freePrimarySlot(ps, *
this);
204 auto et = devices.end();
205 for (
auto rit = devices.rbegin(), ret = devices.rend();
207#ifdef _LIBCPP_VERSION
211 std::span alreadyRemoved(std::to_address(rit.base()), et - rit.base());
213 std::span alreadyRemoved{rit.base(), et};
215 (*rit)->testRemove(alreadyRemoved);
219 for (
auto ps :
xrange(4)) {
220 for (
auto ss :
xrange(4)) {
221 if (externalSlots[ps][ss]) {
225 if (externalPrimSlots[ps]) {
226 slotManager.testRemoveExternalSlot(ps, *
this);
228 if (expandedSlots[ps]) {
240static void loadHelper(
XMLDocument& doc,
const std::string& filename)
243 doc.
load(filename,
"msxconfig2.dtd");
244 }
catch (XMLException& e) {
246 "Loading of hardware configuration failed: ",
251static std::string getFilename(std::string_view type, std::string_view name)
257 type,
'/', name,
".xml"));
258 }
catch (MSXException& e) {
263 type,
'/', name,
"/hardwareconfig.xml"));
264 }
catch (MSXException&) {
272 loadHelper(doc, getFilename(type, name));
275void HardwareConfig::load(std::string_view type_)
277 std::string filename = getFilename(type_, hwName);
278 loadHelper(config, filename);
280 assert(!userName.empty());
292 const auto& primSlot = psElem->getAttribute(
"slot");
294 if (psElem->getAttributeValueAsBool(
"external",
false)) {
297 "Cannot mark unspecified primary slot '",
298 primSlot.getValue(),
"' as external");
300 if (psElem->hasChildren()) {
303 " is marked as external, but that would only "
304 "make sense if its <primary> tag would be "
307 createExternalSlot(ps);
310 for (
const auto* ssElem : psElem->getChildren(
"secondary")) {
311 auto secSlot = ssElem->getAttributeValue(
"slot");
313 if ((-16 <= ss) && (ss <= -1) && (ss != ps)) {
315 "Invalid secondary slot specification: \"",
319 if ((ss >= -128) && (0 <= ps) && (ps < 4) &&
328 ps = getAnyFreePrimarySlot();
330 ps = getSpecificFreePrimarySlot(-ps - 1);
332 auto& mutablePrimSlot =
const_cast<XMLAttribute&
>(primSlot);
335 createExpandedSlot(ps);
336 if (ssElem->getAttributeValueAsBool(
"external",
false)) {
337 if (ssElem->hasChildren()) {
339 "Secondary slot ", ps,
'-', ss,
340 " is marked as external, but that would "
341 "only make sense if its <secondary> tag "
344 createExternalSlot(ps, ss);
352 byte initialPrimarySlots = 0;
353 if (
const auto* slotMap =
getConfig().findChild(
"slotmap")) {
354 for (
const auto* child : slotMap->getChildren(
"map")) {
355 int page = child->getAttributeValueAsInt(
"page", -1);
356 if (page < 0 || page > 3) {
357 throw MSXException(
"Invalid or missing page in slotmap entry");
359 int slot = child->getAttributeValueAsInt(
"slot", -1);
360 if (slot < 0 || slot > 3) {
361 throw MSXException(
"Invalid or missing slot in slotmap entry");
363 unsigned offset = page * 2;
364 initialPrimarySlots &=
byte(~(3 << offset));
365 initialPrimarySlots |=
byte(slot << offset);
368 return initialPrimarySlots;
379 for (
const auto& c : elem.getChildren()) {
380 const auto& childName = c.getName();
381 if (childName ==
"primary") {
383 }
else if (childName ==
"secondary") {
387 DeviceConfig(*
this, c, primary, secondary));
389 addDevice(std::move(device));
397void HardwareConfig::createExternalSlot(
int ps)
400 assert(!externalPrimSlots[ps]);
401 externalPrimSlots[ps] =
true;
404void HardwareConfig::createExternalSlot(
int ps,
int ss)
407 assert(!externalSlots[ps][ss]);
408 externalSlots[ps][ss] =
true;
411void HardwareConfig::createExpandedSlot(
int ps)
413 if (!expandedSlots[ps]) {
415 expandedSlots[ps] =
true;
419int HardwareConfig::getAnyFreePrimarySlot()
422 assert(!allocatedPrimarySlots[ps]);
423 allocatedPrimarySlots[ps] =
true;
427int HardwareConfig::getSpecificFreePrimarySlot(
unsigned slot)
430 assert(!allocatedPrimarySlots[ps]);
431 allocatedPrimarySlots[ps] =
true;
435void HardwareConfig::addDevice(std::unique_ptr<MSXDevice> device)
438 devices.push_back(std::move(device));
441void HardwareConfig::setName(std::string_view proposedName)
448 name =
strCat(proposedName,
" (", ++n,
')');
453void HardwareConfig::setSlot(std::string_view slotName)
455 for (
const auto* psElem :
getDevicesElem().getChildren(
"primary")) {
456 const auto& primSlot = psElem->getAttribute(
"slot");
457 if (primSlot.getValue() ==
"any") {
458 auto& mutablePrimSlot =
const_cast<XMLAttribute&
>(primSlot);
464static constexpr std::initializer_list<enum_string<HardwareConfig::Type>> configTypeInfo = {
477template<
typename Archive>
485 if (ar.versionAtLeast(version, 6)) {
486 ar.serialize(
"config", config);
489 ar.serialize(
"config", elem);
492 if (ar.versionAtLeast(version, 2)) {
493 if (ar.versionAtLeast(version, 4)) {
494 ar.serialize(
"context", context);
496 std::unique_ptr<FileContext> ctxt;
497 ar.serialize(
"context", ctxt);
498 if (ctxt) context = *ctxt;
505 if constexpr (Archive::IS_LOADER) {
516 for (
auto& d : devices) {
517 ar.serializePolymorphic(
"device", *d);
519 ar.serialize(
"name", name);
520 if (ar.versionAtLeast(version, 5)) {
521 ar.serialize(
"type", type);
523 assert(Archive::IS_LOADER);
static int getSlotNum(std::string_view slot)
void createExternalSlot(int ps)
void testRemoveExternalSlot(int ps, const HardwareConfig &allowed) const
void removeExternalSlot(int ps)
int allocateAnyPrimarySlot(const HardwareConfig &hwConfig)
int allocateSpecificPrimarySlot(unsigned slot, const HardwareConfig &hwConfig)
virtual Interpreter & getInterpreter()=0
static std::unique_ptr< MSXDevice > create(const DeviceConfig &conf)
std::string resolve(std::string_view filename) const
std::string_view getRomFilename() const
static std::unique_ptr< HardwareConfig > createRomConfig(MSXMotherBoard &motherBoard, std::string_view romFile, std::string_view slotName, std::span< const TclObject > options)
static std::unique_ptr< HardwareConfig > createMachineConfig(MSXMotherBoard &motherBoard, std::string machineName)
void serialize(Archive &ar, unsigned version)
void setFileContext(FileContext &&ctxt)
HardwareConfig(MSXMotherBoard &motherBoard, std::string hwName)
const XMLElement & getConfig() const
byte parseSlotMap() const
Parses a slot mapping.
static void loadConfig(XMLDocument &doc, std::string_view type, std::string_view name)
static std::unique_ptr< HardwareConfig > createExtensionConfig(MSXMotherBoard &motherBoard, std::string extensionName, std::string_view slotName)
void testRemove() const
Checks whether this HardwareConfig can be deleted.
const XMLElement & getDevicesElem() const
void testUnsetExpanded(int ps, std::span< const std::unique_ptr< MSXDevice > > allowed) const
void unsetExpanded(int ps)
bool isExpanded(int ps) const
HardwareConfig * findExtension(std::string_view extensionName)
void setMachineConfig(HardwareConfig *machineConfig)
void freeUserName(const std::string &hwName, const std::string &userName)
const HardwareConfig * getMachineConfig() const
MSXCPUInterface & getCPUInterface()
std::string getUserName(const std::string &hwName)
Keep track of which 'usernames' are in use.
CommandController & getCommandController()
CartridgeSlotManager & getSlotManager()
void removeDevice(MSXDevice &device)
void addDevice(MSXDevice &device)
All MSXDevices should be registered by the MotherBoard.
void setValue(const char *value_)
void generateList(XMLElement &parent, const char *itemName, Range &&range, UnaryOp op)
const char * allocateString(std::string_view str)
XMLElement * allocateElement(const char *name)
XMLAttribute * allocateAttribute(const char *name, const char *value)
void load(const std::string &filename, std::string_view systemID)
XMLElement * setData(const char *data_)
const XMLElement * findChild(std::string_view childName) const
const XMLElement & getChild(std::string_view childName) const
ChildRange getChildren() const
std::optional< Context > context
string_view getDirName(string_view path)
Returns the directory portion of a path.
bool isRegularFile(const Stat &st)
string getAbsolutePath(string_view path)
Transform given path into an absolute path.
string_view getFilename(string_view path)
Returns the file portion of a path name.
This file implemented 3 utility functions:
const FileContext & systemFileContext()
uint8_t byte
8 bit unsigned integer
FileContext configFileContext(string_view path, string_view hwDescr, string_view userName)
ArgsInfo valueArg(std::string_view name, T &value)
std::vector< TclObject > parseTclArgs(Interpreter &interp, std::span< const TclObject > inArgs, std::span< const ArgsInfo > table)
const FileContext & userFileContext()
constexpr void fill(ForwardRange &&range, const T &value)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
#define SERIALIZE_ENUM(TYPE, INFO)
TemporaryString tmpStrCat(Ts &&... ts)
static std::unique_ptr< FileContext > getLastSerializedFileContext()
constexpr auto xrange(T e)