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