openMSX
MSXMultiMemDevice.cc
Go to the documentation of this file.
1 #include "MSXMultiMemDevice.hh"
2 #include "DummyDevice.hh"
3 #include "MSXCPUInterface.hh"
4 #include "TclObject.hh"
5 #include "likely.hh"
6 #include "ranges.hh"
7 #include "stl.hh"
8 #include "unreachable.hh"
9 #include "view.hh"
10 #include <cassert>
11 
12 namespace openmsx {
13 
14 MSXMultiMemDevice::Range::Range(
15  unsigned base_, unsigned size_, MSXDevice& device_)
16  : base(base_), size(size_), device(&device_)
17 {
18 }
19 
20 bool MSXMultiMemDevice::Range::operator==(const Range& other) const
21 {
22  return (base == other.base) &&
23  (size == other.size) &&
24  (device == other.device);
25 }
26 
27 
29  : MSXMultiDevice(hwConf)
30 {
31  // add sentinel at the end
32  ranges.emplace_back(0x0000, 0x10000, getCPUInterface().getDummyDevice());
33 }
34 
36 {
37  assert(empty());
38 }
39 
40 static bool isInside(unsigned x, unsigned start, unsigned size)
41 {
42  return (x - start) < size;
43 }
44 
45 static bool overlap(unsigned start1, unsigned size1,
46  unsigned start2, unsigned size2)
47 {
48  return (isInside(start1, start2, size2)) ||
49  (isInside(start1 + size1 - 1, start2, size2));
50 }
51 
52 bool MSXMultiMemDevice::canAdd(int base, int size)
53 {
54  return ranges::none_of(view::drop_back(ranges, 1), [&](auto& rn) {
55  return overlap(base, size, rn.base, rn.size);
56  });
57 }
58 
59 void MSXMultiMemDevice::add(MSXDevice& device, int base, int size)
60 {
61  assert(canAdd(base, size));
62  ranges.insert(begin(ranges), Range(base, size, device));
63 }
64 
65 void MSXMultiMemDevice::remove(MSXDevice& device, int base, int size)
66 {
67  ranges.erase(rfind_unguarded(ranges, Range(base, size, device)));
68 }
69 
70 std::vector<MSXDevice*> MSXMultiMemDevice::getDevices() const
71 {
73  [](auto& rn) { return rn.device; }));
74 }
75 
76 std::string MSXMultiMemDevice::getName() const
77 {
78  TclObject list;
79  getNameList(list);
80  return std::string(list.getString());
81 }
83 {
84  for (auto& r : ranges) {
85  const auto& name = r.device->getName();
86  if (!name.empty()) {
87  result.addListElement(name);
88  }
89  }
90 }
91 
92 const MSXMultiMemDevice::Range& MSXMultiMemDevice::searchRange(unsigned address) const
93 {
94  for (auto& r : ranges) {
95  if (isInside(address, r.base, r.size)) {
96  return r;
97  }
98  }
99  UNREACHABLE; return ranges.back();
100 }
101 
102 MSXDevice* MSXMultiMemDevice::searchDevice(unsigned address) const
103 {
104  return searchRange(address).device;
105 }
106 
107 byte MSXMultiMemDevice::readMem(word address, EmuTime::param time)
108 {
109  return searchDevice(address)->readMem(address, time);
110 }
111 
112 byte MSXMultiMemDevice::peekMem(word address, EmuTime::param time) const
113 {
114  return searchDevice(address)->peekMem(address, time);
115 }
116 
117 void MSXMultiMemDevice::writeMem(word address, byte value, EmuTime::param time)
118 {
119  searchDevice(address)->writeMem(address, value, time);
120 }
121 
123 {
124  assert((start & CacheLine::HIGH) == start); // start is aligned
125  // Because start is aligned we don't need to wory about the begin
126  // address of the range. But we must make sure the end of the range
127  // doesn't only fill a partial cacheline.
128  const auto& range = searchRange(start);
129  if (unlikely(((range.base + range.size) & CacheLine::HIGH) == start)) {
130  // The end of this memory device only fills a partial
131  // cacheline. This can't be cached.
132  return nullptr;
133  }
134  return searchDevice(start)->getReadCacheLine(start);
135 }
136 
138 {
139  assert((start & CacheLine::HIGH) == start);
140  const auto& range = searchRange(start);
141  if (unlikely(((range.base + range.size) & CacheLine::HIGH) == start)) {
142  return nullptr;
143  }
144  return searchDevice(start)->getWriteCacheLine(start);
145 }
146 
147 } // namespace openmsx
auto transform(Range &&range, UnaryOp op)
Definition: view.hh:306
virtual byte * getWriteCacheLine(word start) const
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing...
Definition: MSXDevice.cc:449
MSXMultiMemDevice(const HardwareConfig &hwConf)
std::string getName() const override
Returns a human-readable name for this device.
#define unlikely(x)
Definition: likely.hh:15
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
virtual byte readMem(word address, EmuTime::param time)
Read a byte from a location at a certain time from this device.
Definition: MSXDevice.cc:409
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:420
constexpr unsigned HIGH
Definition: CacheLine.hh:10
void remove(MSXDevice &device, int base, int size)
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
bool none_of(InputRange &&range, UnaryPredicate pred)
Definition: ranges.hh:131
size_t size(std::string_view utf8)
void add(MSXDevice &device, int base, int size)
void getNameList(TclObject &result) const override
Returns list of name(s) of this device.
virtual byte peekMem(word address, EmuTime::param time) const
Read a byte from a given memory location.
Definition: MSXDevice.cc:426
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
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:415
constexpr bool operator==(const uint128 &a, const uint128 &b)
Definition: uint128.hh:241
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX...
Definition: MSXDevice.hh:31
std::string_view getString() const
Definition: TclObject.cc:102
auto drop_back(Range &&range, size_t n)
Definition: view.hh:294
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
void addListElement(T t)
Definition: TclObject.hh:121
std::vector< MSXDevice * > getDevices() const
Definition: ranges.hh:20
byte * getWriteCacheLine(word start) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing...
MSXCPUInterface & getCPUInterface() const
Definition: MSXDevice.cc:137
constexpr KeyMatrixPosition x
Keyboard bindings.
Definition: Keyboard.cc:1377
const byte * getReadCacheLine(word start) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading...
auto rfind_unguarded(RANGE &range, const VAL &val)
Similar to the find(_if)_unguarded functions above, but searches from the back to front...
Definition: stl.hh:152
bool canAdd(int base, int size)
void writeMem(word address, byte value, EmuTime::param time) override
Write a given byte to a given location at a certain time to this device.
auto to_vector(Range &&range) -> std::vector< detail::ToVectorType< T, decltype(std::begin(range))>>
Definition: stl.hh:311
#define UNREACHABLE
Definition: unreachable.hh:38