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