openMSX
CheckedRam.cc
Go to the documentation of this file.
1 #include "CheckedRam.hh"
2 #include "MSXCPU.hh"
3 #include "MSXMotherBoard.hh"
4 #include "DeviceConfig.hh"
5 #include "GlobalSettings.hh"
6 #include "StringSetting.hh"
7 #include "likely.hh"
8 #include <cassert>
9 
10 namespace openmsx {
11 
12 static std::bitset<CacheLine::SIZE> getBitSetAllTrue()
13 {
14  std::bitset<CacheLine::SIZE> result;
15  result.set();
16  return result;
17 }
18 
19 CheckedRam::CheckedRam(const DeviceConfig& config, const std::string& name,
20  const std::string& description, unsigned size)
21  : completely_initialized_cacheline(size / CacheLine::SIZE, false)
22  , uninitialized(size / CacheLine::SIZE, getBitSetAllTrue())
23  , ram(config, name, description, size)
24  , msxcpu(config.getMotherBoard().getCPU())
25  , umrCallback(config.getGlobalSettings().getUMRCallBackSetting())
26 {
27  umrCallback.getSetting().attach(*this);
28  init();
29 }
30 
32 {
33  umrCallback.getSetting().detach(*this);
34 }
35 
36 byte CheckedRam::read(unsigned addr)
37 {
38  unsigned line = addr >> CacheLine::BITS;
39  if (unlikely(!completely_initialized_cacheline[line])) {
40  if (unlikely(uninitialized[line][addr & CacheLine::LOW])) {
41  umrCallback.execute(addr, ram.getName());
42  }
43  }
44  return ram[addr];
45 }
46 
47 const byte* CheckedRam::getReadCacheLine(unsigned addr) const
48 {
49  return (completely_initialized_cacheline[addr >> CacheLine::BITS])
50  ? &ram[addr] : nullptr;
51 }
52 
53 byte* CheckedRam::getWriteCacheLine(unsigned addr) const
54 {
55  return (completely_initialized_cacheline[addr >> CacheLine::BITS])
56  ? const_cast<byte*>(&ram[addr]) : nullptr;
57 }
58 
59 byte* CheckedRam::getRWCacheLines(unsigned addr, unsigned size) const
60 {
61  // TODO optimize
62  unsigned num = size >> CacheLine::BITS;
63  unsigned first = addr >> CacheLine::BITS;
64  for (unsigned i = 0; i < num; ++i) {
65  if (!completely_initialized_cacheline[first + i]) {
66  return nullptr;
67  }
68  }
69  return const_cast<byte*>(&ram[addr]);
70 }
71 
72 void CheckedRam::write(unsigned addr, const byte value)
73 {
74  unsigned line = addr >> CacheLine::BITS;
75  if (unlikely(!completely_initialized_cacheline[line])) {
76  uninitialized[line][addr & CacheLine::LOW] = false;
77  if (unlikely(uninitialized[line].none())) {
78  completely_initialized_cacheline[line] = true;
79  // This invalidates way too much stuff. But because
80  // (locally) we don't know exactly how this class ie
81  // being used in the MSXDevice, there's no easy way to
82  // figure out what exactly should be invalidated.
83  //
84  // This is anyway only a debug feature (usually it's
85  // not in use), therefor it's OK to implement this in a
86  // easy/slow way rather than complex/fast.
87  msxcpu.invalidateAllSlotsRWCache(0, 0x10000);
88  }
89  }
90  ram[addr] = value;
91 }
92 
94 {
95  ram.clear();
96  init();
97 }
98 
99 void CheckedRam::init()
100 {
101  if (umrCallback.getValue().empty()) {
102  // there is no callback function,
103  // do as if everything is initialized
104  completely_initialized_cacheline.assign(
105  completely_initialized_cacheline.size(), true);
106  uninitialized.assign(
107  uninitialized.size(), std::bitset<CacheLine::SIZE>());
108  } else {
109  // new callback function, forget about initialized areas
110  completely_initialized_cacheline.assign(
111  completely_initialized_cacheline.size(), false);
112  uninitialized.assign(
113  uninitialized.size(), getBitSetAllTrue());
114  }
115  msxcpu.invalidateAllSlotsRWCache(0, 0x10000);
116 }
117 
118 void CheckedRam::update(const Setting& setting)
119 {
120  assert(&setting == &umrCallback.getSetting());
121  (void)setting;
122  init();
123 }
124 
125 } // namespace openmsx
openmsx::CheckedRam::getWriteCacheLine
byte * getWriteCacheLine(unsigned addr) const
Definition: CheckedRam.cc:53
unlikely
#define unlikely(x)
Definition: likely.hh:15
openmsx::Subject::detach
void detach(Observer< T > &observer)
Definition: Subject.hh:56
openmsx::CheckedRam::~CheckedRam
~CheckedRam()
Definition: CheckedRam.cc:31
openmsx::CheckedRam::read
byte read(unsigned addr)
Definition: CheckedRam.cc:36
openmsx::DeviceConfig
Definition: DeviceConfig.hh:19
utf8::unchecked::size
size_t size(std::string_view utf8)
Definition: utf8_unchecked.hh:227
MSXCPU.hh
openmsx::Ram::getName
const std::string & getName() const
Definition: Ram.cc:96
openmsx::CheckedRam::getRWCacheLines
byte * getRWCacheLines(unsigned addr, unsigned size) const
Definition: CheckedRam.cc:59
openmsx::Subject::attach
void attach(Observer< T > &observer)
Definition: Subject.hh:50
CheckedRam.hh
likely.hh
StringSetting.hh
openmsx::CheckedRam::clear
void clear()
Definition: CheckedRam.cc:93
openmsx::MSXCPU::invalidateAllSlotsRWCache
void invalidateAllSlotsRWCache(word start, unsigned size)
Invalidate the CPU its cache for the interval [start, start + size) For example MSXMemoryMapper and M...
Definition: MSXCPU.cc:182
openmsx::CheckedRam::CheckedRam
CheckedRam(const DeviceConfig &config, const std::string &name, const std::string &description, unsigned size)
Definition: CheckedRam.cc:19
openmsx::TclCallback::getValue
TclObject getValue() const
Definition: TclCallback.cc:35
openmsx::CheckedRam::write
void write(unsigned addr, byte value)
Definition: CheckedRam.cc:72
openmsx::TclCallback::execute
TclObject execute()
Definition: TclCallback.cc:40
openmsx::CacheLine::SIZE
constexpr unsigned SIZE
Definition: CacheLine.hh:7
openmsx::TclCallback::getSetting
StringSetting & getSetting() const
Definition: TclCallback.hh:31
openmsx::TclObject::empty
bool empty() const
Definition: TclObject.hh:159
GlobalSettings.hh
openmsx::Ram::clear
void clear(byte c=0xff)
Definition: Ram.cc:52
openmsx::CacheLine::LOW
constexpr unsigned LOW
Definition: CacheLine.hh:9
openmsx::CacheLine::BITS
constexpr unsigned BITS
Definition: CacheLine.hh:6
DeviceConfig.hh
openmsx
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
MSXMotherBoard.hh
openmsx::CheckedRam::getReadCacheLine
const byte * getReadCacheLine(unsigned addr) const
Definition: CheckedRam.cc:47