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