openMSX
RomBlocks.cc
Go to the documentation of this file.
1 #include "CliComm.hh"
2 #include "RomBlocks.hh"
3 #include "SRAM.hh"
4 #include "Math.hh"
5 #include "serialize.hh"
6 #include "unreachable.hh"
7 
8 namespace openmsx {
9 
10 template<bool C, class T, class F> struct if_log2_ : F {};
11 template< class T, class F> struct if_log2_<true, T, F> : T {};
12 template<unsigned A, unsigned R = 0> struct log2
13  : if_log2_<A == 1, std::integral_constant<int, R>, log2<A / 2, R + 1>> {};
14 
15 // minimal attempt to avoid seeing this warning too often
16 static Sha1Sum alreadyWarnedForSha1Sum;
17 
18 template <unsigned BANK_SIZE>
20  const DeviceConfig& config, Rom&& rom_,
21  unsigned debugBankSizeShift)
22  : MSXRom(config, std::move(rom_))
23  , romBlockDebug(
24  *this, blockNr, 0x0000, 0x10000,
25  log2<BANK_SIZE>::value, debugBankSizeShift)
26 {
27  static_assert(Math::isPowerOfTwo(BANK_SIZE), "BANK_SIZE must be a power of two");
28  auto extendedSize = (rom.getSize() + BANK_SIZE - 1) & ~(BANK_SIZE - 1);
29  if (extendedSize != rom.getSize() && alreadyWarnedForSha1Sum != rom.getOriginalSHA1()) {
30  config.getCliComm().printWarning(
31  "(uncompressed) ROM image filesize was not a multiple "
32  "of ", BANK_SIZE / 1024, "kB (which is required for mapper type ",
33  config.findChild("mappertype")->getData(), "), so we "
34  "padded it to be correct. But if the ROM you are "
35  "running was just dumped, the dump is probably not "
36  "complete/correct!");
37  alreadyWarnedForSha1Sum = rom.getOriginalSHA1();
38  }
39  rom.addPadding(extendedSize);
40  nrBlocks = rom.getSize() / BANK_SIZE;
41  assert((nrBlocks * BANK_SIZE) == rom.getSize());
42 
43  // by default no extra mappable memory block
44  extraMem = nullptr;
45  extraSize = 0;
46 
47  // Default mask: wraps at end of ROM image.
48  blockMask = nrBlocks - 1;
49  for (unsigned i = 0; i < NUM_BANKS; i++) {
50  setRom(i, 0);
51  }
52 }
53 
54 template <unsigned BANK_SIZE>
56 
57 template <unsigned BANK_SIZE>
58 byte RomBlocks<BANK_SIZE>::peekMem(word address, EmuTime::param /*time*/) const
59 {
60  return bankPtr[address / BANK_SIZE][address & BANK_MASK];
61 }
62 
63 template <unsigned BANK_SIZE>
64 byte RomBlocks<BANK_SIZE>::readMem(word address, EmuTime::param time)
65 {
66  return RomBlocks<BANK_SIZE>::peekMem(address, time);
67 }
68 
69 template <unsigned BANK_SIZE>
71 {
72  return &bankPtr[address / BANK_SIZE][address & BANK_MASK];
73 }
74 
75 template <unsigned BANK_SIZE>
76 void RomBlocks<BANK_SIZE>::setBank(byte region, const byte* adr, int block)
77 {
78  assert("address passed to setBank() is not serializable" &&
79  ((adr == unmappedRead) ||
80  ((&rom[0] <= adr) && (adr <= &rom[rom.getSize() - 1])) ||
81  (sram && (&(*sram)[0] <= adr) &&
82  (adr <= &(*sram)[sram->getSize() - 1])) ||
83  ((extraMem <= adr) && (adr <= &extraMem[extraSize - 1]))));
84  bankPtr[region] = adr;
85  blockNr[region] = block; // only for debuggable
86  invalidateMemCache(region * BANK_SIZE, BANK_SIZE);
87 }
88 
89 template <unsigned BANK_SIZE>
91 {
92  setBank(region, unmappedRead, 255);
93 }
94 
95 template <unsigned BANK_SIZE>
97 {
98  extraMem = mem;
99  extraSize = size;
100 }
101 
102 template <unsigned BANK_SIZE>
103 void RomBlocks<BANK_SIZE>::setRom(byte region, unsigned block)
104 {
105  // Note: Some cartridges have a number of blocks that is not a power of 2,
106  // for those we have to make an exception for "block < nrBlocks".
107  block = (block < nrBlocks) ? block : block & blockMask;
108  if (block < nrBlocks) {
109  setBank(region, &rom[block * BANK_SIZE], block);
110  } else {
111  setBank(region, unmappedRead, 255);
112  }
113 }
114 
115 // version 1: initial version
116 // version 2: added blockNr
117 template <unsigned BANK_SIZE>
118 template<typename Archive>
119 void RomBlocks<BANK_SIZE>::serialize(Archive& ar, unsigned /*version*/)
120 {
121  // skip MSXRom base class
122  ar.template serializeBase<MSXDevice>(*this);
123 
124  if (sram) ar.serialize("sram", *sram);
125 
126  unsigned offsets[NUM_BANKS];
127  unsigned romSize = rom.getSize();
128  unsigned sramSize = sram ? sram->getSize() : 0;
129  if (ar.isLoader()) {
130  ar.serialize("banks", offsets);
131  for (unsigned i = 0; i < NUM_BANKS; ++i) {
132  if (offsets[i] == unsigned(-1)) {
133  bankPtr[i] = unmappedRead;
134  } else if (offsets[i] < romSize) {
135  bankPtr[i] = &rom[offsets[i]];
136  } else if (offsets[i] < (romSize + sramSize)) {
137  assert(sram);
138  bankPtr[i] = &(*sram)[offsets[i] - romSize];
139  } else if (offsets[i] < (romSize + sramSize + extraSize)) {
140  bankPtr[i] = &extraMem[offsets[i] - romSize - sramSize];
141  } else {
142  // TODO throw
143  UNREACHABLE;
144  }
145  }
146  } else {
147  for (unsigned i = 0; i < NUM_BANKS; ++i) {
148  if (bankPtr[i] == unmappedRead) {
149  offsets[i] = unsigned(-1);
150  } else if ((&rom[0] <= bankPtr[i]) &&
151  (bankPtr[i] <= &rom[romSize - 1])) {
152  offsets[i] = unsigned(bankPtr[i] - &rom[0]);
153  } else if (sram && (&(*sram)[0] <= bankPtr[i]) &&
154  (bankPtr[i] <= &(*sram)[sramSize - 1])) {
155  offsets[i] = unsigned(bankPtr[i] - &(*sram)[0] + romSize);
156  } else if ((extraMem <= bankPtr[i]) &&
157  (bankPtr[i] <= &extraMem[extraSize - 1])) {
158  offsets[i] = unsigned(bankPtr[i] - extraMem + romSize + sramSize);
159  } else {
160  UNREACHABLE;
161  }
162  }
163  ar.serialize("banks", offsets);
164  }
165 
166  // Commented out because versioning doesn't work correct on subclasses
167  // that don't override the serialize() method (e.g. RomPlain)
168  /*if (ar.versionAtLeast(version, 2)) {
169  ar.serialize("blockNr", blockNr);
170  } else {
171  assert(ar.isLoader());
172  // set dummy value, anyway only used for debuggable
173  for (unsigned i = 0; i < NUM_BANKS; ++i) {
174  blockNr[i] = 255;
175  }
176  }*/
177 }
178 
179 template class RomBlocks<0x1000>;
180 template class RomBlocks<0x2000>;
181 template class RomBlocks<0x4000>;
185 
186 } // namespace openmsx
void setRom(byte region, unsigned block)
Selects a block of the ROM image for reading in a certain region.
Definition: RomBlocks.cc:103
const XMLElement * findChild(string_view name) const
Definition: DeviceConfig.cc:61
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
STL namespace.
void setBank(byte region, const byte *adr, int block)
Sets the memory visible for reading in a certain region.
Definition: RomBlocks.cc:76
CliComm & getCliComm() const
Definition: DeviceConfig.cc:18
const std::string & getData() const
Definition: XMLElement.hh:33
This class represents the result of a sha1 calculation (a 160-bit value).
Definition: sha1.hh:19
const Sha1Sum & getOriginalSHA1() const
Definition: Rom.cc:354
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition: RomBlocks.cc:58
static const unsigned NUM_BANKS
Definition: RomBlocks.hh:17
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
Definition: RomBlocks.cc:64
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
const byte * bankPtr[NUM_BANKS]
Definition: RomBlocks.hh:81
byte blockNr[NUM_BANKS]
Definition: RomBlocks.hh:83
const byte * getReadCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading...
Definition: RomBlocks.cc:70
unsigned getSize() const
Definition: Rom.hh:32
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
void addPadding(unsigned newSize, byte filler=0xff)
Definition: Rom.cc:371
static byte unmappedRead[0x10000]
Definition: MSXDevice.hh:274
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:840
~RomBlocks() override
static const unsigned BANK_SIZE
Definition: RomBlocks.hh:16
void setUnmapped(byte region)
Select &#39;unmapped&#39; memory for this region.
Definition: RomBlocks.cc:90
void serialize(Archive &ar, unsigned version)
Definition: RomBlocks.cc:119
std::unique_ptr< SRAM > sram
Definition: RomBlocks.hh:82
static const unsigned BANK_MASK
Definition: RomBlocks.hh:18
void setExtraMemory(const byte *mem, unsigned size)
Inform this base class of extra mapable memory block.
Definition: RomBlocks.cc:96
RomBlocks(const DeviceConfig &config, Rom &&rom, unsigned debugBankSizeShift=0)
Constructor.
Definition: RomBlocks.cc:19
constexpr bool isPowerOfTwo(unsigned a)
Is the given number an integer power of 2? Not correct for zero (according to this test 0 is a power ...
Definition: Math.hh:34
constexpr auto size(const C &c) -> decltype(c.size())
Definition: span.hh:62
void printWarning(string_view message)
Definition: CliComm.cc:20
void invalidateMemCache(word start, unsigned size)
Invalidate CPU memory-mapping cache.
Definition: MSXDevice.cc:458
#define UNREACHABLE
Definition: unreachable.hh:38