openMSX
RomBlocks.cc
Go to the documentation of this file.
1 #include "RomBlocks.hh"
2 #include "SRAM.hh"
3 #include "MSXException.hh"
4 #include "StringOp.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 template <unsigned BANK_SIZE>
17  const DeviceConfig& config, Rom&& rom_,
18  unsigned debugBankSizeShift)
19  : MSXRom(config, std::move(rom_))
20  , romBlockDebug(
21  *this, blockNr, 0x0000, 0x10000,
22  log2<BANK_SIZE>::value, debugBankSizeShift)
23  , nrBlocks(rom.getSize() / BANK_SIZE)
24 {
25  if ((nrBlocks * BANK_SIZE) != rom.getSize()) {
27  "(uncompressed) ROM image filesize must be a multiple of " <<
28  BANK_SIZE / 1024 << " kB (for this mapper type).");
29  }
30  // by default no extra mappable memory block
31  extraMem = nullptr;
32  extraSize = 0;
33 
34  // Default mask: wraps at end of ROM image.
35  blockMask = nrBlocks - 1;
36  for (unsigned i = 0; i < NUM_BANKS; i++) {
37  setRom(i, 0);
38  }
39 }
40 
41 template <unsigned BANK_SIZE>
43 
44 template <unsigned BANK_SIZE>
46 {
47  return bankPtr[address / BANK_SIZE][address & BANK_MASK];
48 }
49 
50 template <unsigned BANK_SIZE>
52 {
53  return &bankPtr[address / BANK_SIZE][address & BANK_MASK];
54 }
55 
56 template <unsigned BANK_SIZE>
57 void RomBlocks<BANK_SIZE>::setBank(byte region, const byte* adr, int block)
58 {
59  assert("address passed to setBank() is not serializable" &&
60  ((adr == unmappedRead) ||
61  ((&rom[0] <= adr) && (adr <= &rom[rom.getSize() - 1])) ||
62  (sram && (&(*sram)[0] <= adr) &&
63  (adr <= &(*sram)[sram->getSize() - 1])) ||
64  ((extraMem <= adr) && (adr <= &extraMem[extraSize - 1]))));
65  bankPtr[region] = adr;
66  blockNr[region] = block; // only for debuggable
67  invalidateMemCache(region * BANK_SIZE, BANK_SIZE);
68 }
69 
70 template <unsigned BANK_SIZE>
72 {
73  setBank(region, unmappedRead, 255);
74 }
75 
76 template <unsigned BANK_SIZE>
78 {
79  extraMem = mem;
80  extraSize = size;
81 }
82 
83 template <unsigned BANK_SIZE>
84 void RomBlocks<BANK_SIZE>::setRom(byte region, int block)
85 {
86  // Note: Some cartridges have a number of blocks that is not a power of 2,
87  // for those we have to make an exception for "block < nrBlocks".
88  block = (block < nrBlocks) ? block : block & blockMask;
89  if (block < nrBlocks) {
90  setBank(region, &rom[block * BANK_SIZE], block);
91  } else {
92  setBank(region, unmappedRead, 255);
93  }
94 }
95 
96 // version 1: initial version
97 // version 2: added blockNr
98 template <unsigned BANK_SIZE>
99 template<typename Archive>
100 void RomBlocks<BANK_SIZE>::serialize(Archive& ar, unsigned /*version*/)
101 {
102  // skip MSXRom base class
103  ar.template serializeBase<MSXDevice>(*this);
104 
105  if (sram) ar.serialize("sram", *sram);
106 
107  unsigned offsets[NUM_BANKS];
108  unsigned romSize = rom.getSize();
109  unsigned sramSize = sram ? sram->getSize() : 0;
110  if (ar.isLoader()) {
111  ar.serialize("banks", offsets);
112  for (unsigned i = 0; i < NUM_BANKS; ++i) {
113  if (offsets[i] == unsigned(-1)) {
114  bankPtr[i] = unmappedRead;
115  } else if (offsets[i] < romSize) {
116  bankPtr[i] = &rom[offsets[i]];
117  } else if (offsets[i] < (romSize + sramSize)) {
118  assert(sram);
119  bankPtr[i] = &(*sram)[offsets[i] - romSize];
120  } else if (offsets[i] < (romSize + sramSize + extraSize)) {
121  bankPtr[i] = &extraMem[offsets[i] - romSize - sramSize];
122  } else {
123  // TODO throw
124  UNREACHABLE;
125  }
126  }
127  } else {
128  for (unsigned i = 0; i < NUM_BANKS; ++i) {
129  if (bankPtr[i] == unmappedRead) {
130  offsets[i] = unsigned(-1);
131  } else if ((&rom[0] <= bankPtr[i]) &&
132  (bankPtr[i] <= &rom[romSize - 1])) {
133  offsets[i] = unsigned(bankPtr[i] - &rom[0]);
134  } else if (sram && (&(*sram)[0] <= bankPtr[i]) &&
135  (bankPtr[i] <= &(*sram)[sramSize - 1])) {
136  offsets[i] = unsigned(bankPtr[i] - &(*sram)[0] + romSize);
137  } else if ((extraMem <= bankPtr[i]) &&
138  (bankPtr[i] <= &extraMem[extraSize - 1])) {
139  offsets[i] = unsigned(bankPtr[i] - extraMem + romSize + sramSize);
140  } else {
141  UNREACHABLE;
142  }
143  }
144  ar.serialize("banks", offsets);
145  }
146 
147  // Commented out because versioning doesn't work correct on subclasses
148  // that don't override the serialize() method (e.g. RomPlain)
149  /*if (ar.versionAtLeast(version, 2)) {
150  ar.serialize("blockNr", blockNr);
151  } else {
152  assert(ar.isLoader());
153  // set dummy value, anyway only used for debuggable
154  for (unsigned i = 0; i < NUM_BANKS; ++i) {
155  blockNr[i] = 255;
156  }
157  }*/
158 }
159 
160 template class RomBlocks<0x1000>;
161 template class RomBlocks<0x2000>;
162 template class RomBlocks<0x4000>;
166 
167 } // namespace openmsx
void setRom(byte region, int block)
Selects a block of the ROM image for reading in a certain region.
Definition: RomBlocks.cc:84
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
STL namespace.
const byte * getReadCacheLine(word start) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading...
Definition: RomBlocks.cc:51
void setBank(byte region, const byte *adr, int block)
Sets the memory visible for reading in a certain region.
Definition: RomBlocks.cc:57
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:45
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
const byte * bankPtr[NUM_BANKS]
Definition: RomBlocks.hh:80
byte blockNr[NUM_BANKS]
Definition: RomBlocks.hh:82
size_t size() const
unsigned getSize() const
Definition: Rom.hh:32
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
static byte unmappedRead[0x10000]
Definition: MSXDevice.hh:268
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:840
static const unsigned BANK_SIZE
Definition: RomBlocks.hh:16
void setUnmapped(byte region)
Select &#39;unmapped&#39; memory for this region.
Definition: RomBlocks.cc:71
void serialize(Archive &ar, unsigned version)
Definition: RomBlocks.cc:100
std::unique_ptr< SRAM > sram
Definition: RomBlocks.hh:81
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:77
RomBlocks(const DeviceConfig &config, Rom &&rom, unsigned debugBankSizeShift=0)
Constructor.
Definition: RomBlocks.cc:16
void invalidateMemCache(word start, unsigned size)
Invalidate CPU memory-mapping cache.
Definition: MSXDevice.cc:452
#define UNREACHABLE
Definition: unreachable.hh:35