openMSX
MSXDevice.cc
Go to the documentation of this file.
1 #include "MSXDevice.hh"
2 #include "XMLElement.hh"
3 #include "MSXMotherBoard.hh"
4 #include "HardwareConfig.hh"
6 #include "MSXCPUInterface.hh"
7 #include "CacheLine.hh"
8 #include "TclObject.hh"
9 #include "Math.hh"
10 #include "MSXException.hh"
11 #include "one_of.hh"
12 #include "ranges.hh"
13 #include "serialize.hh"
14 #include "stl.hh"
15 #include "unreachable.hh"
16 #include "xrange.hh"
17 #include <cassert>
18 #include <cstring>
19 
20 namespace openmsx {
21 
22 MSXDevice::MSXDevice(const DeviceConfig& config, std::string_view name)
23  : deviceConfig(config)
24 {
25  initName(name);
26 }
27 
29  : deviceConfig(config)
30 {
31  initName(getDeviceConfig().getAttributeValue("id"));
32 }
33 
34 void MSXDevice::initName(std::string_view name)
35 {
36  deviceName = name;
37  if (getMotherBoard().findDevice(deviceName)) {
38  unsigned n = 0;
39  do {
40  deviceName = strCat(name, " (", ++n, ')');
41  } while (getMotherBoard().findDevice(deviceName));
42  }
43 }
44 
46 {
47  staticInit();
48 
49  lockDevices();
50  registerSlots();
51  registerPorts();
52 }
53 
55 {
56  unregisterPorts();
57  unregisterSlots();
58  unlockDevices();
59  assert(referencedBy.empty());
60 }
61 
62 void MSXDevice::staticInit()
63 {
64  static bool alreadyInit = false;
65  if (alreadyInit) return;
66  alreadyInit = true;
67 
68  memset(unmappedRead, 0xFF, sizeof(unmappedRead));
69 }
70 
72 {
74 }
75 
76 void MSXDevice::testRemove(span<const std::unique_ptr<MSXDevice>> removed) const
77 {
78  // Typically 'referencedBy' contains very few elements, so a simple
79  // O(n*m) algorithm is fine.
80  std::string err;
81  for (const auto* dev : referencedBy) {
82  if (!contains(removed, dev, [](const auto& d) { return d.get(); })) {
83  strAppend(err, ' ', dev->getName());
84  }
85  }
86  if (!err.empty()) {
87  throw MSXException("Still in use by:", err);
88  }
89 }
90 
91 void MSXDevice::lockDevices()
92 {
93  // This code can only handle backward references: the thing that is
94  // referenced must already be instantiated, we don't try to change the
95  // instantiation order. For the moment this is good enough (only ADVRAM
96  // (an extension) uses it to refer to the VDP (inside a machine)). If
97  // needed we can implement something more sophisticated later without
98  // changing the format of the config files.
99  for (const auto* c : getDeviceConfig().getChildren("device")) {
100  auto name = c->getAttributeValue("idref");
101  auto* dev = getMotherBoard().findDevice(name);
102  if (!dev) {
103  throw MSXException(
104  "Unsatisfied dependency: '", getName(),
105  "' depends on unavailable device '",
106  name, "'.");
107  }
108  references.push_back(dev);
109  dev->referencedBy.push_back(this);
110  }
111 }
112 
113 void MSXDevice::unlockDevices()
114 {
115  for (auto& r : references) {
116  move_pop_back(r->referencedBy, rfind_unguarded(r->referencedBy, this));
117  }
118 }
119 
121 {
122  // init() must already be called
123  return references;
124 }
125 
126 EmuTime::param MSXDevice::getCurrentTime() const
127 {
128  return getMotherBoard().getCurrentTime();
129 }
131 {
132  return getMotherBoard().getCPU();
133 }
135 {
136  return getMotherBoard().getCPUInterface();
137 }
139 {
140  return getMotherBoard().getScheduler();
141 }
143 {
144  return getMotherBoard().getMSXCliComm();
145 }
147 {
148  return getMotherBoard().getReactor();
149 }
151 {
153 }
155 {
156  return getMotherBoard().getLedStatus();
157 }
159 {
161 }
162 
163 void MSXDevice::registerSlots()
164 {
165  MemRegions tmpMemRegions;
166  unsigned align = getBaseSizeAlignment();
167  assert(Math::ispow2(align));
168  for (const auto* m : getDeviceConfig().getChildren("mem")) {
169  unsigned base = m->getAttributeValueAsInt("base", 0);
170  unsigned size = m->getAttributeValueAsInt("size", 0);
171  if ((base >= 0x10000) || (size > 0x10000) || ((base + size) > 0x10000)) {
172  throw MSXException(
173  "Invalid memory specification for device ",
174  getName(), " should be in range "
175  "[0x0000,0x10000).");
176  }
177  if (((base & (align - 1)) || (size & (align - 1))) &&
178  !allowUnaligned()) {
179  throw MSXException(
180  "invalid memory specification for device ",
181  getName(), " should be aligned on at least 0x",
182  hex_string<4>(align), '.');
183  }
184  tmpMemRegions.emplace_back(BaseSize{base, size});
185  }
186  if (tmpMemRegions.empty()) {
187  return;
188  }
189 
190  // find primary and secondary slot specification
191  auto& slotManager = getMotherBoard().getSlotManager();
192  auto* primaryConfig = getDeviceConfig2().getPrimary();
193  auto* secondaryConfig = getDeviceConfig2().getSecondary();
194  if (primaryConfig) {
195  ps = slotManager.getSlotNum(primaryConfig->getAttributeValue("slot"));
196  } else {
197  throw MSXException("Invalid memory specification");
198  }
199  if (secondaryConfig) {
200  auto ss_str = secondaryConfig->getAttributeValue("slot");
201  ss = slotManager.getSlotNum(ss_str);
202  if ((-16 <= ss) && (ss <= -1) && (ss != ps)) {
203  throw MSXException(
204  "Invalid secondary slot specification: \"",
205  ss_str, "\".");
206  }
207  } else {
208  ss = 0;
209  }
210 
211  // This is only for backwards compatibility: in the past we added extra
212  // attributes "primary_slot" and "secondary_slot" (in each MSXDevice
213  // config) instead of changing the 'any' value of the slot attribute of
214  // the (possibly shared) <primary> and <secondary> tags. When loading
215  // an old savestate these tags can still occur, so keep this code. Also
216  // remove these attributes to convert to the new format.
217  auto& mutableConfig = const_cast<XMLElement&>(getDeviceConfig());
218  if (auto** primSlotPtr = mutableConfig.findAttributePointer("primary_slot")) {
219  ps = slotManager.getSlotNum((*primSlotPtr)->getValue());
220  mutableConfig.removeAttribute(primSlotPtr);
221  if (auto** secSlotPtr = mutableConfig.findAttributePointer("secondary_slot")) {
222  ss = slotManager.getSlotNum((*secSlotPtr)->getValue());
223  mutableConfig.removeAttribute(secSlotPtr);
224  }
225  }
226 
227  // decode special values for 'ss'
228  if ((-128 <= ss) && (ss < 0)) {
229  if ((0 <= ps) && (ps < 4) &&
230  getCPUInterface().isExpanded(ps)) {
231  ss += 128;
232  } else {
233  ss = 0;
234  }
235  }
236 
237  // decode special values for 'ps'
238  if (ps == -256) {
239  slotManager.getAnyFreeSlot(ps, ss);
240  } else if (ps < 0) {
241  // specified slot by name (carta, cartb, ...)
242  slotManager.getSpecificSlot(-ps - 1, ps, ss);
243  } else {
244  // numerical specified slot (0, 1, 2, 3)
245  }
246  assert((0 <= ps) && (ps <= 3));
247 
248  if (!getCPUInterface().isExpanded(ps)) {
249  ss = -1;
250  }
251 
252  // Store actual slot in config. This has two purposes:
253  // - Make sure that devices that are grouped under the same
254  // <primary>/<secondary> tags actually use the same slot. (This
255  // matters when the value of some of the slot attributes is "any").
256  // - Fix the slot number so that it remains the same after a
257  // savestate/loadstate.
258  assert(primaryConfig);
259  XMLDocument& doc = deviceConfig.getXMLDocument();
260  doc.setAttribute(*primaryConfig, "slot", doc.allocateString(tmpStrCat(ps)));
261  if (secondaryConfig) {
262  doc.setAttribute(*secondaryConfig, "slot", doc.allocateString(
263  (ss == -1) ? std::string_view("X") : tmpStrCat(ss)));
264  } else {
265  if (ss != -1) {
266  throw MSXException(
267  "Missing <secondary> tag for device", getName());
268  }
269  }
270 
271  int logicalSS = (ss == -1) ? 0 : ss;
272  for (auto& r : tmpMemRegions) {
274  *this, ps, logicalSS, r.base, r.size);
275  memRegions.push_back(r);
276  }
277 
278  // Mark the slot as 'in-use' so that future searches for free external
279  // slots don't return this slot anymore. If the slot was not an
280  // external slot, this call has no effect. Multiple MSXDevices from the
281  // same extension (the same HardwareConfig) can all allocate the same
282  // slot (later they should also all free this slot).
283  slotManager.allocateSlot(ps, ss, getHardwareConfig());
284 }
285 
286 void MSXDevice::unregisterSlots()
287 {
288  if (memRegions.empty()) return;
289 
290  int logicalSS = (ss == -1) ? 0 : ss;
291  for (const auto& [base, size] : memRegions) {
293  *this, ps, logicalSS, base, size);
294  }
295 
296  // See comments above about allocateSlot() for more details:
297  // - has no effect for non-external slots
298  // - can be called multiple times for the same slot
300 }
301 
302 void MSXDevice::getVisibleMemRegion(unsigned& base, unsigned& size) const
303 {
304  // init() must already be called
305  if (memRegions.empty()) {
306  base = 0;
307  size = 0;
308  return;
309  }
310 
311  auto lowest = min_value(memRegions, &BaseSize::base);
312  auto highest = max_value(memRegions, &BaseSize::end);
313  assert(lowest <= highest);
314  base = lowest;
315  size = highest - lowest;
316 }
317 
318 void MSXDevice::registerPorts()
319 {
320  // First calculate 'inPort' and 'outPorts' ..
321  for (const auto* i : getDeviceConfig().getChildren("io")) {
322  unsigned base = i->getAttributeValueAsInt("base", 0);
323  unsigned num = i->getAttributeValueAsInt("num", 0);
324  auto type = i->getAttributeValue("type", "IO");
325  if (((base + num) > 256) || (num == 0) ||
326  (type != one_of("I", "O", "IO"))) {
327  throw MSXException("Invalid IO port specification");
328  }
329  if (type != "O") { // "I" or "IO"
330  inPorts.setPosN(base, num);
331  }
332  if (type != "I") { // "O" or "IO"
333  outPorts.setPosN(base, num);
334  }
335  }
336  // .. and only then register the ports. This filters possible overlaps.
337  inPorts.foreachSetBit([&](auto port) {
338  getCPUInterface().register_IO_In(byte(port), this);
339  });
340  outPorts.foreachSetBit([&](auto port) {
341  getCPUInterface().register_IO_Out(byte(port), this);
342  });
343 }
344 
345 void MSXDevice::unregisterPorts()
346 {
347  inPorts.foreachSetBit([&](auto port) {
348  getCPUInterface().unregister_IO_In(byte(port), this);
349  });
350  outPorts.foreachSetBit([&](auto port) {
351  getCPUInterface().unregister_IO_Out(byte(port), this);
352  });
353 }
354 
355 
356 void MSXDevice::reset(EmuTime::param /*time*/)
357 {
358  // nothing
359 }
360 
362 {
363  return 0xFF;
364 }
365 
366 void MSXDevice::powerDown(EmuTime::param /*time*/)
367 {
368  // nothing
369 }
370 
371 void MSXDevice::powerUp(EmuTime::param time)
372 {
373  reset(time);
374 }
375 
376 const std::string& MSXDevice::getName() const
377 {
378  return deviceName;
379 }
380 
382 {
383  result.addListElement(getName());
384 }
385 
387 {
388  result.addDictKeyValue("type", getDeviceConfig().getName());
389  getExtraDeviceInfo(result);
390 }
391 
393 {
394  // nothing
395 }
396 
398 {
399  return CacheLine::SIZE;
400 }
401 
402 
403 byte MSXDevice::readIO(word /*port*/, EmuTime::param /*time*/)
404 {
405  // read from unmapped IO
406  return 0xFF;
407 }
408 
409 void MSXDevice::writeIO(word /*port*/, byte /*value*/, EmuTime::param /*time*/)
410 {
411  // write to unmapped IO, do nothing
412 }
413 
414 byte MSXDevice::peekIO(word /*port*/, EmuTime::param /*time*/) const
415 {
416  return 0xFF;
417 }
418 
419 
420 byte MSXDevice::readMem(word /*address*/, EmuTime::param /*time*/)
421 {
422  // read from unmapped memory
423  return 0xFF;
424 }
425 
426 const byte* MSXDevice::getReadCacheLine(word /*start*/) const
427 {
428  return nullptr; // uncacheable
429 }
430 
431 void MSXDevice::writeMem(word /*address*/, byte /*value*/,
432  EmuTime::param /*time*/)
433 {
434  // write to unmapped memory, do nothing
435 }
436 
437 byte MSXDevice::peekMem(word address, EmuTime::param /*time*/) const
438 {
439  word base = address & CacheLine::HIGH;
440  if (const byte* cache = getReadCacheLine(base)) {
441  word offset = address & CacheLine::LOW;
442  return cache[offset];
443  } else {
444  // peek not supported for this device
445  return 0xFF;
446  }
447 }
448 
449 void MSXDevice::globalWrite(word /*address*/, byte /*value*/,
450  EmuTime::param /*time*/)
451 {
452  UNREACHABLE;
453 }
454 
455 void MSXDevice::globalRead(word /*address*/, EmuTime::param /*time*/)
456 {
457  UNREACHABLE;
458 }
459 
460 byte* MSXDevice::getWriteCacheLine(word /*start*/) const
461 {
462  return nullptr; // uncacheable
463 }
464 
465 
466 // calls 'action(<start2>, <size2>, args..., ps, ss)'
467 // with 'start', 'size' clipped to each of the ranges in 'memRegions'
468 template<typename Action, typename... Args>
469 void MSXDevice::clip(unsigned start, unsigned size, Action action, Args... args)
470 {
471  int ss2 = (ss != -1) ? ss : 0;
472  unsigned end = start + size;
473  for (auto [base, fullBsize] : memRegions) {
474  // split on 16kB boundaries
475  while (fullBsize > 0) {
476  unsigned bsize = std::min(fullBsize, ((base + 0x4000) & ~0x3fff) - base);
477 
478  unsigned baseEnd = base + bsize;
479  // intersect [start, end) with [base, baseEnd) -> [clipStart, clipEnd)
480  unsigned clipStart = std::max(start, base);
481  unsigned clipEnd = std::min(end, baseEnd);
482  if (clipStart < clipEnd) { // non-empty
483  unsigned clipSize = clipEnd - clipStart;
484  action(clipStart, clipSize, args..., ps, ss2);
485  }
486 
487  base += bsize;
488  fullBsize -= bsize;
489  }
490  }
491 }
492 
493 void MSXDevice::invalidateDeviceRWCache(unsigned start, unsigned size)
494 {
495  clip(start, size, [&](auto... args) { getCPUInterface().invalidateRWCache(args...); });
496 }
497 void MSXDevice::invalidateDeviceRCache(unsigned start, unsigned size)
498 {
499  clip(start, size, [&](auto... args) { getCPUInterface().invalidateRCache(args...); });
500 }
501 void MSXDevice::invalidateDeviceWCache(unsigned start, unsigned size)
502 {
503  clip(start, size, [&](auto... args) { getCPUInterface().invalidateWCache(args...); });
504 }
505 
506 void MSXDevice::fillDeviceRWCache(unsigned start, unsigned size, byte* rwData)
507 {
508  fillDeviceRWCache(start, size, rwData, rwData);
509 }
510 void MSXDevice::fillDeviceRWCache(unsigned start, unsigned size, const byte* rData, byte* wData)
511 {
512  assert(!allowUnaligned());
513  clip(start, size, [&](auto... args) { getCPUInterface().fillRWCache(args...); }, rData, wData);
514 }
515 void MSXDevice::fillDeviceRCache(unsigned start, unsigned size, const byte* rData)
516 {
517  assert(!allowUnaligned());
518  clip(start, size, [&](auto... args) { getCPUInterface().fillRCache(args...); }, rData);
519 }
520 void MSXDevice::fillDeviceWCache(unsigned start, unsigned size, byte* wData)
521 {
522  assert(!allowUnaligned());
523  clip(start, size, [&](auto... args) { getCPUInterface().fillWCache(args...); }, wData);
524 }
525 
526 template<typename Archive>
527 void MSXDevice::serialize(Archive& ar, unsigned /*version*/)
528 {
529  // When this method is called, the method init() has already been
530  // called (thus also registerSlots() and registerPorts()).
531  ar.serialize("name", deviceName);
532 }
534 
535 } // namespace openmsx
void setPosN(size_t pos, size_t n)
Starting from position 'pos', set the 'n' following bits to '1'.
void foreachSetBit(Operation op) const
Execute the given operation 'op' for all '1' bits.
Definition: one_of.hh:7
void freeSlot(int ps, int ss, const HardwareConfig &hwConfig)
XMLElement * getSecondary() const
Definition: DeviceConfig.hh:56
XMLDocument & getXMLDocument()
Definition: DeviceConfig.cc:38
XMLElement * getPrimary() const
Definition: DeviceConfig.hh:52
MSXMotherBoard & getMotherBoard() const
void register_IO_Out(byte port, MSXDevice *device)
Devices can register their Out ports.
void invalidateRWCache(word start, unsigned size, int ps, int ss)
void register_IO_In(byte port, MSXDevice *device)
Devices can register their In ports.
void fillWCache(unsigned start, unsigned size, byte *wData, int ps, int ss)
void unregister_IO_In(byte port, MSXDevice *device)
void invalidateRCache(word start, unsigned size, int ps, int ss)
void fillRWCache(unsigned start, unsigned size, const byte *rData, byte *wData, int ps, int ss)
void registerMemDevice(MSXDevice &device, int ps, int ss, int base, int size)
Devices can register themself in the MSX slotstructure.
void invalidateWCache(word start, unsigned size, int ps, int ss)
void unregisterMemDevice(MSXDevice &device, int ps, int ss, int base, int size)
void unregister_IO_Out(byte port, MSXDevice *device)
void fillRCache(unsigned start, unsigned size, const byte *rData, int ps, int ss)
bool isExpanded(int ps) const
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition: MSXDevice.hh:33
MSXMotherBoard & getMotherBoard() const
Get the mother board this device belongs to.
Definition: MSXDevice.cc:71
virtual void init()
Definition: MSXDevice.cc:45
void invalidateDeviceRCache()
Definition: MSXDevice.hh:210
void fillDeviceWCache(unsigned start, unsigned size, byte *wData)
Definition: MSXDevice.cc:520
PluggingController & getPluggingController() const
Definition: MSXDevice.cc:158
virtual void powerUp(EmuTime::param time)
This method is called when MSX is powered up.
Definition: MSXDevice.cc:371
const DeviceConfig & getDeviceConfig2() const
Definition: MSXDevice.hh:234
void fillDeviceRWCache(unsigned start, unsigned size, byte *rwData)
Calls MSXCPUInterface::fillXXCache() for the specific (part of) the slot that this device is located ...
Definition: MSXDevice.cc:506
virtual ~MSXDevice()=0
Definition: MSXDevice.cc:54
CliComm & getCliComm() const
Definition: MSXDevice.cc:142
virtual const byte * getReadCacheLine(word start) const
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
Definition: MSXDevice.cc:426
void invalidateDeviceWCache()
Definition: MSXDevice.hh:211
void getDeviceInfo(TclObject &result) const
Get device info.
Definition: MSXDevice.cc:386
virtual void writeIO(word port, byte value, EmuTime::param time)
Write a byte to a given IO port at a certain time to this device.
Definition: MSXDevice.cc:409
virtual byte readIRQVector()
Gets IRQ vector used in IM2.
Definition: MSXDevice.cc:361
virtual void globalWrite(word address, byte value, EmuTime::param time)
Global writes.
Definition: MSXDevice.cc:449
Reactor & getReactor() const
Definition: MSXDevice.cc:146
virtual bool allowUnaligned() const
By default we don't allow unaligned <mem> specifications in the config file.
Definition: MSXDevice.hh:291
virtual unsigned getBaseSizeAlignment() const
The 'base' and 'size' attribute values need to be at least aligned to CacheLine::SIZE.
Definition: MSXDevice.cc:397
MSXDevice(const MSXDevice &)=delete
const XMLElement & getDeviceConfig() const
Get the configuration section for this device.
Definition: MSXDevice.hh:231
std::vector< MSXDevice * > Devices
Definition: MSXDevice.hh:38
virtual byte readMem(word address, EmuTime::param time)
Read a byte from a location at a certain time from this device.
Definition: MSXDevice.cc:420
virtual void getExtraDeviceInfo(TclObject &result) const
Definition: MSXDevice.cc:392
std::string deviceName
Definition: MSXDevice.hh:321
void getVisibleMemRegion(unsigned &base, unsigned &size) const
Returns the range where this device is visible in memory.
Definition: MSXDevice.cc:302
virtual void writeMem(word address, byte value, EmuTime::param time)
Write a given byte to a given location at a certain time to this device.
Definition: MSXDevice.cc:431
virtual byte peekIO(word port, EmuTime::param time) const
Read a byte from a given IO port.
Definition: MSXDevice.cc:414
virtual byte peekMem(word address, EmuTime::param time) const
Read a byte from a given memory location.
Definition: MSXDevice.cc:437
MSXCPU & getCPU() const
Definition: MSXDevice.cc:130
const HardwareConfig & getHardwareConfig() const
Returns the hardwareconfig this device belongs to.
Definition: MSXDevice.hh:44
virtual const std::string & getName() const
Returns a human-readable name for this device.
Definition: MSXDevice.cc:376
static byte unmappedRead[0x10000]
Definition: MSXDevice.hh:301
LedStatus & getLedStatus() const
Definition: MSXDevice.cc:154
void serialize(Archive &ar, unsigned version)
Definition: MSXDevice.cc:527
void invalidateDeviceRWCache()
Calls MSXCPUInterface::invalidateXXCache() for the specific (part of) the slot that this device is lo...
Definition: MSXDevice.hh:209
Scheduler & getScheduler() const
Definition: MSXDevice.cc:138
virtual void getNameList(TclObject &result) const
Returns list of name(s) of this device.
Definition: MSXDevice.cc:381
virtual byte * getWriteCacheLine(word start) const
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
Definition: MSXDevice.cc:460
void fillDeviceRCache(unsigned start, unsigned size, const byte *rData)
Definition: MSXDevice.cc:515
CommandController & getCommandController() const
Definition: MSXDevice.cc:150
void testRemove(span< const std::unique_ptr< MSXDevice >> removed) const
Checks whether this device can be removed (no other device has a reference to it).
Definition: MSXDevice.cc:76
const Devices & getReferences() const
Get the device references that are specified for this device.
Definition: MSXDevice.cc:120
virtual void powerDown(EmuTime::param time)
This method is called when MSX is powered down.
Definition: MSXDevice.cc:366
virtual void globalRead(word address, EmuTime::param time)
Global reads.
Definition: MSXDevice.cc:455
virtual void reset(EmuTime::param time)
This method is called on reset.
Definition: MSXDevice.cc:356
EmuTime::param getCurrentTime() const
Definition: MSXDevice.cc:126
MSXCPUInterface & getCPUInterface() const
Definition: MSXDevice.cc:134
virtual byte readIO(word port, EmuTime::param time)
Read a byte from an IO port at a certain time from this device.
Definition: MSXDevice.cc:403
PluggingController & getPluggingController()
MSXCPUInterface & getCPUInterface()
EmuTime::param getCurrentTime()
Convenience method: This is the same as getScheduler().getCurrentTime().
CartridgeSlotManager & getSlotManager()
MSXDevice * findDevice(std::string_view name)
Find a MSXDevice by name.
CommandController & getCommandController()
Central administration of Connectors and Pluggables.
Contains the main loop of openMSX.
Definition: Reactor.hh:68
void addListElement(const T &t)
Definition: TclObject.hh:129
void addDictKeyValue(const Key &key, const Value &value)
Definition: TclObject.hh:143
void setAttribute(XMLElement &elem, const char *attrName, const char *attrValue)
Definition: XMLElement.cc:209
Definition: span.hh:126
constexpr bool ispow2(T x) noexcept
Is the given number an integral power of two? That is, does it have exactly one 1-bit in binary repre...
Definition: Math.hh:57
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:269
constexpr vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:287
constexpr unsigned LOW
Definition: CacheLine.hh:9
constexpr unsigned HIGH
Definition: CacheLine.hh:10
constexpr unsigned SIZE
Definition: CacheLine.hh:7
This file implemented 3 utility functions:
Definition: Autofire.cc:9
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
size_t size(std::string_view utf8)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:998
auto min_value(InputIterator first, InputIterator last, Proj proj={})
Definition: stl.hh:205
auto max_value(InputIterator first, InputIterator last, Proj proj={})
Definition: stl.hh:224
void move_pop_back(VECTOR &v, typename VECTOR::iterator it)
Erase the pointed to element from the given vector.
Definition: stl.hh:134
auto rfind_unguarded(RANGE &range, const VAL &val, Proj proj={})
Similar to the find(_if)_unguarded functions above, but searches from the back to front.
Definition: stl.hh:109
constexpr bool contains(ITER first, ITER last, const VAL &val)
Check if a range contains a given value, using linear search.
Definition: stl.hh:32
TemporaryString tmpStrCat(Ts &&... ts)
Definition: strCat.hh:659
std::string strCat(Ts &&...ts)
Definition: strCat.hh:591
void strAppend(std::string &result, Ts &&...ts)
Definition: strCat.hh:669
#define UNREACHABLE
Definition: unreachable.hh:38
constexpr auto end(const zstring_view &x)
Definition: zstring_view.hh:84