24 using std::string_view;
25 using std::unique_ptr;
33 auto result = std::make_unique<HardwareConfig>(
34 motherBoard, move(machineName));
36 result->load(
"machines");
41 MSXMotherBoard& motherBoard,
string extensionName, std::string_view slotname)
43 auto result = std::make_unique<HardwareConfig>(
44 motherBoard, move(extensionName));
45 result->load(
"extensions");
46 result->setName(result->hwName);
48 result->setSlot(slotname);
56 auto result = std::make_unique<HardwareConfig>(motherBoard,
"rom");
57 result->setName(romfile);
60 vector<string_view> ipsfiles;
69 throw MSXException(
"Invalid option \"", args.front().getString(),
'\"');
74 for (
const auto& ips : ipsfiles) {
83 throw MSXException(
"Invalid ROM file: ", resolvedFilename);
87 auto& devices = extension.
addChild(
"devices");
88 auto& primary = devices.addChild(
"primary");
89 primary.addAttribute(
"slot", slotname);
90 auto& secondary = primary.addChild(
"secondary");
91 secondary.addAttribute(
"slot", move(slotname));
92 auto& device = secondary.addChild(
"ROM");
93 device.addAttribute(
"id",
"MSXRom");
94 auto& mem = device.addChild(
"mem");
95 mem.addAttribute(
"base",
"0x0000");
96 mem.addAttribute(
"size",
"0x10000");
97 device.addChild(
"sound").addChild(
"volume",
"9000");
98 device.addChild(
"mappertype", mapper.empty() ?
"auto" : std::move(mapper));
99 device.addChild(
"sramname",
strCat(sramfile,
".SRAM"));
100 auto& rom = device.addChild(
"rom");
101 rom.addChild(
"resolvedFilename", resolvedFilename);
102 rom.addChild(
"filename", move(romfile));
103 if (!ipsfiles.empty()) {
104 auto& patches = rom.addChild(
"patches");
105 for (
auto& s : ipsfiles) {
106 patches.addChild(
"ips", s);
110 result->setConfig(move(extension));
111 result->setFileContext(move(context));
116 : motherBoard(motherBoard_)
117 , hwName(move(hwName_))
119 for (
auto& sub : externalSlots) {
139 while (!devices.empty()) {
144 for (
auto ps :
xrange(4)) {
145 for (
auto ss :
xrange(4)) {
146 if (externalSlots[ps][ss]) {
150 if (externalPrimSlots[ps]) {
151 slotManager.removeExternalSlot(ps);
153 if (expandedSlots[ps]) {
156 if (allocatedPrimarySlots[ps]) {
157 slotManager.freePrimarySlot(ps, *
this);
164 std::vector<MSXDevice*> alreadyRemoved;
166 dev->testRemove(alreadyRemoved);
167 alreadyRemoved.push_back(dev.get());
170 for (
auto ps :
xrange(4)) {
171 for (
auto ss :
xrange(4)) {
172 if (externalSlots[ps][ss]) {
176 if (externalPrimSlots[ps]) {
177 slotManager.testRemoveExternalSlot(ps, *
this);
179 if (expandedSlots[ps]) {
186 const XMLElement& HardwareConfig::getDevicesElem()
const
195 }
catch (XMLException& e) {
197 "Loading of hardware configuration failed: ",
202 static string getFilename(string_view type, string_view name)
208 type,
'/', name,
".xml"));
209 }
catch (MSXException& e) {
214 type,
'/', name,
"/hardwareconfig.xml"));
215 }
catch (MSXException&) {
223 return loadHelper(getFilename(type_, name));
226 void HardwareConfig::load(string_view type_)
228 string filename = getFilename(type_, hwName);
231 assert(!userName.empty());
242 for (
auto& psElem : getDevicesElem().getChildren(
"primary")) {
243 const auto& primSlot = psElem->getAttribute(
"slot");
245 if (psElem->getAttributeAsBool(
"external",
false)) {
248 "Cannot mark unspecified primary slot '",
249 primSlot,
"' as external");
251 if (psElem->hasChildren()) {
254 " is marked as external, but that would only "
255 "make sense if its <primary> tag would be "
258 createExternalSlot(ps);
261 for (
auto& ssElem : psElem->getChildren(
"secondary")) {
262 const auto& secSlot = ssElem->getAttribute(
"slot");
264 if ((-16 <= ss) && (ss <= -1) && (ss != ps)) {
266 "Invalid secondary slot specification: \"",
270 if ((ss >= -128) && (0 <= ps) && (ps < 4) &&
279 ps = getAnyFreePrimarySlot();
281 ps = getSpecificFreePrimarySlot(-ps - 1);
283 auto* mutableElem =
const_cast<XMLElement*
>(psElem);
286 createExpandedSlot(ps);
287 if (ssElem->getAttributeAsBool(
"external",
false)) {
288 if (ssElem->hasChildren()) {
290 "Secondary slot ", ps,
'-', ss,
291 " is marked as external, but that would "
292 "only make sense if its <secondary> tag "
295 createExternalSlot(ps, ss);
303 byte initialPrimarySlots = 0;
304 if (
const auto* slotmap =
getConfig().findChild(
"slotmap")) {
305 for (
const auto* child : slotmap->getChildren(
"map")) {
306 int page = child->getAttributeAsInt(
"page", -1);
307 if (page < 0 || page > 3) {
308 throw MSXException(
"Invalid or missing page in slotmap entry");
310 int slot = child->getAttributeAsInt(
"slot", -1);
311 if (slot < 0 || slot > 3) {
312 throw MSXException(
"Invalid or missing slot in slotmap entry");
314 unsigned offset = page * 2;
315 initialPrimarySlots &= ~(3 << offset);
316 initialPrimarySlots |= slot << offset;
319 return initialPrimarySlots;
331 const auto& childName = c.getName();
332 if (childName ==
"primary") {
334 }
else if (childName ==
"secondary") {
338 DeviceConfig(*
this, c, primary, secondary));
340 addDevice(move(device));
348 void HardwareConfig::createExternalSlot(
int ps)
351 assert(!externalPrimSlots[ps]);
352 externalPrimSlots[ps] =
true;
355 void HardwareConfig::createExternalSlot(
int ps,
int ss)
358 assert(!externalSlots[ps][ss]);
359 externalSlots[ps][ss] =
true;
362 void HardwareConfig::createExpandedSlot(
int ps)
364 if (!expandedSlots[ps]) {
366 expandedSlots[ps] =
true;
370 int HardwareConfig::getAnyFreePrimarySlot()
373 assert(!allocatedPrimarySlots[ps]);
374 allocatedPrimarySlots[ps] =
true;
378 int HardwareConfig::getSpecificFreePrimarySlot(
unsigned slot)
381 assert(!allocatedPrimarySlots[ps]);
382 allocatedPrimarySlots[ps] =
true;
386 void HardwareConfig::addDevice(std::unique_ptr<MSXDevice> device)
389 devices.push_back(move(device));
392 void HardwareConfig::setName(string_view proposedName)
399 name =
strCat(proposedName,
" (", ++n,
')');
404 void HardwareConfig::setSlot(std::string_view slotname)
406 for (
auto& psElem : getDevicesElem().getChildren(
"primary")) {
407 const auto& primSlot = psElem->getAttribute(
"slot");
408 if (primSlot ==
"any") {
409 auto& mutableElem =
const_cast<XMLElement*&
>(psElem);
410 mutableElem->setAttribute(
"slot", slotname);
415 static std::initializer_list<enum_string<HardwareConfig::Type>> configTypeInfo = {
427 template<
typename Archive>
435 if (ar.versionBelow(version, 2)) {
438 ar.serialize(
"config", config);
439 if (ar.versionAtLeast(version, 2)) {
440 if (ar.versionAtLeast(version, 4)) {
441 ar.serialize(
"context", context);
443 std::unique_ptr<FileContext> ctxt;
444 ar.serialize(
"context", ctxt);
445 if (ctxt) context = *ctxt;
463 for (
auto& d : devices) {
464 ar.serializePolymorphic(
"device", *d);
466 ar.serialize(
"name", name);
467 if (ar.versionAtLeast(version, 5)) {
468 ar.serialize(
"type", type);
470 assert(ar.isLoader());
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
const XMLElement & getConfig() const
static XMLElement loadConfig(std::string_view type, std::string_view name)
HardwareConfig(const HardwareConfig &)=delete
void serialize(Archive &ar, unsigned version)
void setFileContext(FileContext &&ctxt)
static std::unique_ptr< HardwareConfig > createExtensionConfig(MSXMotherBoard &motherBoard, std::string extensionName, std::string_view slotname)
static std::unique_ptr< HardwareConfig > createRomConfig(MSXMotherBoard &motherBoard, std::string romfile, std::string slotname, span< const TclObject > options)
byte parseSlotMap() const
Parses a slot mapping.
static std::unique_ptr< HardwareConfig > createMachineConfig(MSXMotherBoard &motherBoard, std::string machineName)
void testRemove() const
Checks whether this HardwareConfig can be deleted.
void testUnsetExpanded(int ps, std::vector< MSXDevice * > allowed) const
void unsetExpanded(int ps)
bool isExpanded(int ps) const
const std::string & getMessage() const &
HardwareConfig * findExtension(std::string_view extensionName)
void setMachineConfig(HardwareConfig *machineConfig)
void freeUserName(const std::string &hwName, const std::string &userName)
MSXCPUInterface & getCPUInterface()
std::string getUserName(const std::string &hwName)
Keep track of which 'usernames' are in use.
CartridgeSlotManager & getSlotManager()
CommandController & getCommandController()
void removeDevice(MSXDevice &device)
const HardwareConfig * getMachineConfig() const
void addDevice(MSXDevice &device)
All MSXDevices should be registered by the MotherBoard.
static std::unique_ptr< FileContext > getLastSerializedFileContext()
XMLElement & addChild(String &&childName)
void setAttribute(String1 &&attrName, String2 &&value)
const Children & getChildren() const
const XMLElement & getChild(std::string_view childName) const
std::unique_ptr< 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.
XMLElement load(const string &filename, string_view systemID)
This file implemented 3 utility functions:
const FileContext & systemFileContext()
FileContext configFileContext(string_view path, string_view hwDescr, string_view userName)
SERIALIZE_ENUM(CassettePlayer::State, stateInfo)
std::vector< TclObject > parseTclArgs(Interpreter &interp, span< const TclObject > inArgs, span< const ArgsInfo > table)
ArgsInfo valueArg(std::string_view name, T &value)
constexpr const char *const filename
FileContext userFileContext(string_view savePath)
void fill(ForwardRange &&range, const T &value)
auto reverse(Range &&range)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
TemporaryString tmpStrCat(Ts &&... ts)
std::string strCat(Ts &&...ts)
constexpr auto xrange(T e)